Compare commits

..
Author SHA1 Message Date
codex b33351117b audit: clarify legacy bootstrap evidence 2026-07-31 13:39:55 +03:00
codex 56dcce42f6 audit: document legacy P_Rec_Annot loading chain 2026-07-31 13:39:29 +03:00
30 changed files with 303 additions and 998 deletions
-129
View File
@@ -1,129 +0,0 @@
# AGENTS.md
## Назначение проекта
Этот репозиторий содержит аудит, архитектуру, исходный код, тесты, runtime
evidence и документацию миграции корпоративной экосистемы Autodesk AutoCAD
Plant 3D 2019 на Autodesk AutoCAD Plant 3D 2026.
Конечная цель — функционально эквивалентная рабочая схема Plant 3D 2026:
корпоративный Launcher, локальная доставка и активация пакетов, managed
плагины, команды, Ribbon, Plant project integration, DataLinks, Ortho,
аннотации, обновление, диагностика и rollback. Миграция не считается
завершённой после успешной компиляции: необходима runtime-проверка реальных
сценариев в Plant 3D 2026.
## Связанные репозитории
- основной Autodesk-репозиторий: `C:\dev\autodesk`;
- Launcher Next: `C:\dev\launcher-next`;
- legacy launcher (read-only): `C:\dev\launcher\git`, `C:\dev\p_serv_starter`;
- legacy P_Rec_Annot (read-only): `C:\dev\autodesk\link\P_Rec_Annot\v1.0.4\repo`.
Legacy и deployed-файлы нельзя изменять без отдельного прямого задания.
## Целевая платформа и принцип миграции
- Autodesk AutoCAD Plant 3D 2026, series R25.1, Windows x64, .NET 8;
- использовать реальные Autodesk 2026 managed assemblies;
- managed package загружается локально, не напрямую с UNC;
- Autodesk DLL нельзя коммитить, помещать в package/fixture или публиковать.
Переносится функциональное поведение, а не историческая структура файлов. Не
воспроизводить без отдельного доказательства 20 последовательных `NETLOAD`,
legacy LISP bootstrap, `OrthoLoader.dll`, загрузку с сети или прежние
workaround. Предпочтительная цепочка:
`Launcher Next → versioned local package → один managed entry assembly → internal dependencies → commands and Ribbon`.
## Статус legacy-команд
Ни одна активная команда Plant 3D 2019 не исчезает молча. Для каждой команды
фиксируется ровно один статус: `IMPLEMENTED`, `RUNTIME_VERIFIED`,
`REPLACED_WITH_NATIVE`, `RETIRED_APPROVED` или `BLOCKED_WITH_REASON`.
Aliases сохраняются, пока их удаление не утверждено отдельно.
## Runtime уровни
`Smoke` проверяет assembly load, регистрацию команд, Plant context, Ribbon,
отсутствие необработанных исключений и отсутствие записи в DWG.
`DryRun` проверяет реальные Plant data, Ortho/sheet/view definitions, DataLinks,
Plant objects, детерминированный план и отсутствие записи в DWG/project DB.
`Apply` разрешается только отдельным явным заданием: write guard, ограниченная
DWG transaction, тестовая копия проекта, baseline, rollback/UNDO, duplicate
protection и runtime evidence обязательны. Apply нельзя включать только
локальной конфигурацией.
## Runtime важнее предположений
Build и unit tests не доказывают Autodesk integration. Для
`RUNTIME_VERIFIED` необходимы фактические результаты: команда, module path,
DBMOD, Ribbon, DataLinks, Ortho status, telemetry и состояние файлов после
закрытия. Не выдумывать UI evidence: использовать `null`, `NOT VERIFIED` или
`BLOCKED WITH REASON`.
На тестовой машине реальный Plant 3D запуск разрешён, если он входит в задачу
и есть test branch, локальный fixture, пройденные build/tests, rollback и нет
production deploy. Не создавать искусственный review-gate перед Process.Start.
Остановка допустима лишь после завершения доступной части работы и при
конкретном внешнем blocker: установка, ОС, права, Autodesk runtime, fixture или
необходимость production-данных.
## Test fixtures и отсутствие записи
Fixtures создаются вне Git, например `<TEST_FIXTURE_ROOT>`. Ortho fixture —
настоящий Plant project с Pipe, DataLinks row, line group, Ortho drawing,
Ortho viewport и source-model connection; обычный AutoCAD viewport не годится.
Production DWG/project использовать нельзя без прямого разрешения.
Нельзя коммитить DWG, DCF, Project.xml с runtime-data, project DB, Ortho
generated files или реальные engineering values.
Для Smoke/DryRun проверять DBMOD до/после, SHA-256 содержательных project
files, отсутствие непредусмотренных transactions/DCF/project-metadata writes.
`LastWriteTime` недостаточен. Отделять служебные Plant cache/session files от
содержательных данных.
## Ribbon, механика и evidence
Ribbon — часть продукта: проверять tab, panel, button, command binding, stable
IDs, отсутствие дубликатов при документах/workspace/reinitialization. Команда
может быть отдельно рабочей, но plugin slice не завершён без Ribbon evidence
или отдельного UI defect.
Документировать каждую runtime-цепочку: component/project/class/method,
input/output, Autodesk transaction mode, writes, telemetry, failure code и
rollback action. Документация соответствует фактическому коду.
Evidence содержит только проверенные значения. Не добавлять username, permit,
полный environment, real project paths/line numbers/ObjectId/RowId/properties,
полные logs, local manifest или startup scripts. Путь fixture заменять на
`<TEST_FIXTURE_ROOT>`.
## Warnings и Git
Известный `MSB3277` WindowsBase 4.0.0.0/8.0.0.0 допустим только при полном
совпадении с ранее зафиксированным warning. Новые warnings исследовать; не
подавлять `NoWarn` без причины.
Запрещены force push, amend/rebase опубликованной истории, push binaries,
изменение неизвестного remote и production deployment из test branch. Перед
commit выполнять:
```powershell
git diff --check
git status --short
git diff --cached --check
```
Не смешивать Launcher defect, plugin defect, runtime evidence и unrelated
formatting в одном commit.
## Definition of Done
Срез завершён, когда реализованы код, build/tests, валидный package и требуемый
runtime-сценарий; записаны фактические результаты; выполнен rollback; fixture и
production изолированы; механика документирована; ветка опубликована обычным
push.
-79
View File
@@ -1,79 +0,0 @@
# AGENTS.md — P_Rec_Annot
## Назначение и package
`P_Rec_Annot` — приоритетный Plant 3D 2026 plugin для чтения, планирования и
последующего создания Ortho-аннотаций; это перенос активного legacy поведения
Plant 3D 2019 на .NET 8/Plant 3D 2026.
Единственная assembly для `NETLOAD` — `PRecAnnot.Plant3D2026.dll`.
`PRecAnnot.*.dll` — internal managed dependencies, их нельзя NETLOAD по одной.
Использовать Autodesk 2026 references; Autodesk DLL не включать в bundle.
## Commands и context
Поддерживаемые команды: `PHP_REC_ANNOT`, `PXP-AAV`, `PXP-OA`. Все
регистрируются реальным Autodesk API, работают в Smoke/DryRun, не изменяют DWG
в этих режимах и создают одно usage event на явный вызов.
Project status: `NotFound`, `FoundWithName`, `FoundWithoutDisplayName`,
`Ambiguous`, `Failed`. Никогда не выводить `проект '' найден`; для пустого
display name: `Plant 3D-проект открыт; отображаемое имя не определено.`
Diagnostic code: `PLANT_PROJECT_DISPLAY_NAME_EMPTY`.
Drawing states: `Ortho`, `NotOrtho`, `Ambiguous`, `Failed`. Обычный DWG не
классифицируется как Ortho; для реального Ortho применять Autodesk API и
`OrthoDocUtils.IsValidOrthoDrawing`.
## DryRun и determinism
Pipeline: `Plant context → Ortho detection → sheet/view definitions → viewport
snapshots → DataLinks → Plant properties → independent DTO → deterministic
AnnotationPlan → diagnostics → no write`.
Autodesk objects, transactions и database handles остаются в adapter layer;
Core/Application используют только независимые DTO. На неизменном fixture
повторный DryRun обязан давать тот же PlanId, counts, порядок операций и warning
codes, без side effects. PlanId не включает время, GUID, absolute path,
нестабильный ObjectId или пользовательские данные.
## Write guard, Ribbon, tests
Все writes проходят централизованный write guard; в Smoke/DryRun он всегда
запрещает изменения. Apply не обходится через command handler/adapter.
Ожидаемый Ribbon путь: `Промхимпроект → Аннотации → Аннотировать`. Требуются
stable IDs, отсутствие дублей, binding к `PHP_REC_ANNOT`, устойчивость к
документам/workspace и корректный Terminate.
Unit tests не требуют Autodesk runtime. Runtime evidence отдельно фиксирует
initialization, commands, context, Ortho, DataLinks, plan, Ribbon, DBMOD,
telemetry и shutdown.
Bundle содержит только фактический runtime dependency graph и никогда не
содержит Autodesk DLL, PDB, test assemblies, legacy 2019 assemblies, bin/obj
или production configuration.
Fixture: local Plant 3D 2026 project вне Git с настоящей Pipe, synthetic line
number, Ortho drawing/viewport и SHA baseline до DryRun.
## Ortho source DataLinks and DCF control
DataLinks активного Ortho drawing не являются источником Piping rows. Piping
rows читаются из source model drawing и Piping project part, разрешённых через
Ortho sheet/view definitions.
Перед предположениями об Autodesk runtime API необходимо исследовать текущий
код, доступный legacy usage, assembly metadata и реальные runtime types.
Reflection/runtime inspection применяется только для подтверждения данных,
которых нельзя установить статически. Production resolver не угадывает
Autodesk properties по строковым именам.
Подтверждённый контракт Plant 3D 2026: `IDwgViewDef.DwgQuery` →
`IDwgQuery.ModelFiles` → `ModelFile[].ModelFileName`. При несовпадении типа
возвращать `ORTHO_MODEL_FILES_API_UNSUPPORTED`, без fallback-эвристики.
Проверка DCF выполняется на парных `control` и `DryRun` fixtures, созданных из
одного закрытого состояния проекта. Сравнивать нужно `control delta` с
`DryRun delta`: одинаковые изменения классифицируются как baseline behavior
Plant 3D, а plugin-only изменения блокируют дальнейшую работу.
@@ -1,5 +0,0 @@
# Annotation-plan determinism
`AnnotationPlanBuilder` uses schema version `1`. Its canonical input is the normalized command, source drawing basename, view ID, source snapshots sorted by stable ID, properties sorted by key, membership state, and operations sorted by stable source key and type. Absolute paths, process data, timestamps and runtime ObjectIds are excluded.
Runtime DryRun confirmed equal PlanIds and summaries for two calls of each supported command. Changing a relevant normalized input changes the PlanId.
@@ -1,3 +0,0 @@
# DCF control comparison
`DBMOD` covers only the active DWG. DCF and project metadata require paired control and DryRun fixture copies created from one fully closed state. This comparison has not yet been executed, so plugin-only DCF and metadata deltas remain unverified. Apply remains blocked.
@@ -1,17 +0,0 @@
{
"executionMode": "DryRun",
"planSchemaVersion": 1,
"sourceObjectsRead": 7,
"membershipResolved": 0,
"membershipPartial": 0,
"membershipUnresolved": 7,
"phpRecAnnotPlanIds": ["plan-C5D40DC32505D5D9CFE6D38B", "plan-C5D40DC32505D5D9CFE6D38B"],
"pxpAavPlanIds": ["plan-E4877CA13418D43A17F47AAA", "plan-E4877CA13418D43A17F47AAA"],
"pxpOaPlanIds": ["plan-6C794D25C292E73AA3BDDC31", "plan-6C794D25C292E73AA3BDDC31"],
"summariesDeterministic": true,
"dbmodBefore": 0,
"dbmodAfter": 0,
"launcherSession": "RolledBack",
"dcfControlComparison": null,
"applyModeUsed": false
}
@@ -1,28 +0,0 @@
{
"date": "2026-08-03",
"executionMode": "DryRun",
"plantProjectDetected": true,
"projectDisplayNameStatus": "FoundWithName",
"orthoDetection": "Confirmed",
"viewportCount": 1,
"dataLinksAvailable": true,
"dataLinksSheetToSourceMapping": "resolved-through-piping-project-drawing-id",
"sourceDrawingsResolved": 1,
"sourceDataLinksAvailable": true,
"objectsRead": 7,
"pipeObjectsRead": 7,
"phpRecAnnotRuns": 1,
"pxpAavRuns": null,
"pxpOaRuns": null,
"planId": null,
"repeatedPlanIdEqual": null,
"dbmodBefore": null,
"dbmodAfter": null,
"dwgModified": null,
"dcfModified": null,
"changedProjectFiles": null,
"unhandledExceptions": 0,
"applyModeUsed": false,
"launcherRollback": "RolledBack",
"exactViewportMembership": "not-verified"
}
@@ -1,28 +0,0 @@
# Ortho DryRun runtime result
Date: 2026-08-03
The local test fixture's `TestPipeOrtho.dwg` was detected as Ortho with one
viewport. In `DryRun`, `PHP_REC_ANNOT` ran twice, `PXP-AAV` ran twice, and
`PXP-OA` ran once. All completed without an unhandled exception; `DBMOD` was
`0` before and after.
`PlantProject.Name` was available for this fixture and rendered as
`PRecAnnotTestProject`.
The active Ortho sheet does not expose direct Piping rows and must not be used
as a DataLinks source. Metadata inspection and a sanitized runtime probe
confirmed `IDwgViewDef.DwgQuery.ModelFiles[].ModelFileName` as the source-model
reference. The adapter resolves that reference through
`PipingProject.GetPnPDrawingFiles()` and reads
`DataLinksManager.SelectAcPpRowIds(PnPProjectDrawing.Id)`.
On the latest real DryRun, one source drawing was resolved and seven source
Plant objects were read. `PHP_REC_ANNOT` reported seven skipped operations,
zero writes, zero conflicts, and zero errors. This verifies source-model
DataLinks access; it does not yet verify exact source-object-to-viewport
membership or repeated-plan determinism.
The test fixture SHA baseline changed for `Piping.dcf` before the first DryRun
command. This run therefore does not prove DCF invariance. A paired control
fixture versus DryRun fixture comparison remains required.
@@ -1,39 +0,0 @@
# Ortho source-model mapping
## Confirmed Plant 3D 2026 read path
```text
Active Ortho document
→ OrthoProject.DwgSheetDefinitions
→ IDwgSheetDef.DwgViewDefs
→ IDwgViewDef.DwgQuery.ModelFiles[].ModelFileName
→ PipingProject.GetPnPDrawingFiles()
→ exact normalized-path match to PnPProjectDrawing
→ PnPProjectDrawing.Id
→ DataLinksManager.SelectAcPpRowIds(int dwgid)
→ GetObjectClassname / GetAllProperties
→ independent PlantObjectSnapshot
→ AnnotationPlanBuilder
```
`PlantOrthoViewportReader.ReadViewports` reads the typed DwgQuery contract and
creates an Ortho viewport snapshot. `PlantObjectReader.ReadObjects` resolves
the resulting model-file reference through the Piping project drawing list and
reads DataLinks by project drawing ID. The active Ortho database is not a
Piping-row source.
All calls are read-only. The adapter opens no write transaction and does not
save a drawing, DCF, or project metadata.
## Diagnostics
The source reader returns stable telemetry diagnostics rather than suppressing
the result of a failed query: `ORTHO_SOURCE_DRAWING_NOT_RESOLVED`,
`ORTHO_SOURCE_DRAWING_NOT_IN_PROJECT`, `ORTHO_SOURCE_DRAWING_AMBIGUOUS`,
`PIPING_PROJECT_PART_NOT_FOUND`, `SOURCE_DATALINKS_UNAVAILABLE`,
`SOURCE_DATALINKS_NO_ROWS`, `SOURCE_DATABASE_READ_FAILED`,
`SOURCE_PIPE_ROWS_NOT_FOUND`, or `SOURCE_DATALINKS_READ`.
Exact membership of a source object in a particular Ortho viewport is not yet
implemented. A source-level DryRun plan must not be presented as proof of
viewport membership.
@@ -1,5 +0,0 @@
# Ortho viewport membership
Every source snapshot has an explicit `ViewMembershipStatus`. The current Plant 3D 2026 adapter has no confirmed official object-to-view mapping API, so the seven source objects are `NotResolved` and skipped with `VIEW_MEMBERSHIP_NOT_RESOLVED`. Source presence is not treated as viewport membership.
No geometric heuristic is used as an exact mapping. The next step requires a confirmed generated-entity linkage or documented view mapping.
@@ -1,101 +0,0 @@
# Plant 3D 2026 DwgQuery / ModelFiles API contract
## Scope and method
This report is based on metadata-only inspection of the installed Plant 3D 2026
assemblies. The assemblies were read from `<PLANT3D_2026_INSTALL>` and were not
copied into the repository. Metadata-only inspection was necessary because the
normal PowerShell host cannot load the product's .NET 8 dependencies safely.
Legacy source at the documented local path was not present on this machine, so
there is no legacy API claim in this report.
## Confirmed assemblies
| Assembly | Version | Relevant type |
| --- | --- | --- |
| `PnPDwg2dDef` | `0.0.0.0` | `Autodesk.ProcessPower.Drawings2d.DwgQuery`, `IDwgQuery`, `DwgViewDef`, `IDwgViewDef`, `DwgSheetDef`, `IDwgSheetDef` |
| `PnPDwg2dUtil` | `0.0.0.0` | `Autodesk.ProcessPower.Drawings2d.ModelFile` |
| `PnP3dOrthoProjectPart` | `17.0.60.1` | Ortho project-part integration assembly; the metadata scan found no public DwgQuery declaration there |
`PnPDwg2dDef` and `PnPDwg2dUtil` use `0.0.0.0` assembly versions in the
installed metadata. The supported runtime contract is therefore identified by
the exact public type names below, not by an invented product-version number.
## Confirmed contract
```text
Autodesk.ProcessPower.Drawings2d.IDwgViewDef.DwgQuery
: Autodesk.ProcessPower.Drawings2d.IDwgQuery
Autodesk.ProcessPower.Drawings2d.IDwgQuery.ModelFiles
: Autodesk.ProcessPower.Drawings2d.ModelFile[]
Autodesk.ProcessPower.Drawings2d.ModelFile.ModelFileName
: System.String
Autodesk.ProcessPower.Drawings2d.ModelFile.ModelFileGuid
: System.String
```
`DwgViewDef` implements `IDwgViewDef`; `DwgQuery` implements `IDwgQuery` and
`IDisposable`; `ModelFile` implements `IComparable<ModelFile>`.
`ModelFiles` is an array, not an untyped enumerable. `ModelFileName` is the
only confirmed string field representing the model-file reference. `ModelFileGuid`
is a separate identity field. `IsReferencedDwg` and `Xform` describe reference
state and transform, not a substitute path.
## Public members relevant to source resolution
`IDwgViewDef` exposes `DwgQuery`, `ViewName`, layout/orientation properties,
and `SetClippingPlanes`, `SetLayout`, `SetOrientation`, `Erase`, and `New`.
`IDwgQuery` exposes `ModelFiles`, `Execute`, and `Erase`.
`ModelFile` exposes `ModelFileName`, `ModelFileGuid`, `IsReferencedDwg`, and
`Xform`; its constructors accept a file-name string and optional transform,
reference flag, and GUID.
`IDwgSheetDef.DwgViewDefs` exposes the view-definition collection. Sheet
`DwgName`/`DwgPath` identify the Ortho sheet and must not be used as the source
of Piping DataLinks.
## Current and legacy usage
The original adapter used reflection and tried several possible names
(`ModelFileName`, `Value`, and arbitrary string values). That was not a valid
Plant 3D 2026 contract.
The production read path now uses the confirmed typed chain only:
```text
IDwgViewDef.DwgQuery.ModelFiles[].ModelFileName
```
The legacy source path was unavailable locally, so no legacy source-model or
DataLinks workaround has been imported.
## Runtime evidence
Static metadata cannot prove whether `ModelFileName` is project-relative or
absolute in a concrete Ortho fixture, or whether a particular view has zero,
one, or multiple model files. In DryRun only, setting
`P_REC_ANNOT_DIAGNOSTICS=OrthoStructure` enables a sanitized structure probe.
It records type names, collection counts, null state, string length, and a
one-way value hash; it does not emit paths or engineering data.
On the local DryRun fixture, the runtime probe recorded one view with one
`ModelFile`. The concrete types were `DwgViewDef`, `DwgQueryByBox`, and
`ModelFile[]`; `ModelFileName` was non-null and an absolute fixture-model
reference. The path itself was not retained in repository evidence.
The resolver resolves that reference to exactly one
`PipingProject.GetPnPDrawingFiles()` entry by normalized full-path equality,
then uses the confirmed `DataLinksManager.SelectAcPpRowIds(int dwgid)` overload
with the resolved `PnPProjectDrawing.Id`. It does not open or query the active
Ortho database for Piping rows.
The production resolver has no fallback property-name search. If the exact
contract is unavailable at runtime it reports
`ORTHO_MODEL_FILES_API_UNSUPPORTED` rather than guessing.
@@ -8,7 +8,6 @@ public sealed record RuntimeDiagnostic
}
public enum OrthoDetectionStatus { Confirmed, NotOrtho, Ambiguous, Unsupported, Failed }
public enum PlantProjectDetectionStatus { NotFound, FoundWithName, FoundWithoutDisplayName, Ambiguous, Failed }
public sealed record OrthoDetectionResult
{
@@ -58,12 +57,8 @@ public sealed record PlantObjectSnapshot
public required GeometrySnapshot Geometry { get; init; }
public IReadOnlyDictionary<string, string?> Properties { get; init; } = new Dictionary<string, string?>();
public IReadOnlyList<string> Diagnostics { get; init; } = Array.Empty<string>();
public ViewMembershipStatus MembershipStatus { get; init; } = ViewMembershipStatus.NotResolved;
public IReadOnlyList<string> MembershipEvidenceCodes { get; init; } = Array.Empty<string>();
}
public enum ViewMembershipStatus { NotResolved, Resolved, PartiallyResolved, ObjectOutsideView, Unsupported, Failed }
public sealed record PlantRuntimeContext
{
public bool HasActiveDocument { get; init; }
@@ -71,7 +66,6 @@ public sealed record PlantRuntimeContext
public bool IsOrthoDrawing { get; init; }
public string? DrawingName { get; init; }
public string? ProjectDisplayName { get; init; }
public PlantProjectDetectionStatus ProjectDetectionStatus { get; init; } = PlantProjectDetectionStatus.NotFound;
public IReadOnlyList<OrthoViewportInfo> Viewports { get; init; } = Array.Empty<OrthoViewportInfo>();
public IReadOnlyList<RuntimeDiagnostic> Diagnostics { get; init; } = Array.Empty<RuntimeDiagnostic>();
public OrthoDetectionResult Detection { get; init; } = new() { Status = OrthoDetectionStatus.Unsupported, Evidence = Array.Empty<string>(), Diagnostics = Array.Empty<RuntimeDiagnostic>() };
@@ -80,62 +74,6 @@ public sealed record PlantRuntimeContext
public interface IPlantRuntimeContextReader { PlantRuntimeContext ReadCurrentContext(); }
public interface IOrthoViewportReader { IReadOnlyList<OrthoViewportInfo> 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<string> EvidenceCodes { get; init; } = Array.Empty<string>();
}
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<string, string?> Properties { get; init; } = new Dictionary<string, string?>();
}
public sealed record SourceDrawingReadResult
{
public required OrthoSourceDrawingReference Source { get; init; }
public IReadOnlyList<SourcePlantObjectSnapshot> Objects { get; init; } = Array.Empty<SourcePlantObjectSnapshot>();
public IReadOnlyList<RuntimeDiagnostic> Diagnostics { get; init; } = Array.Empty<RuntimeDiagnostic>();
}
public interface IOrthoSourceDrawingResolver
{
IReadOnlyList<OrthoSourceDrawingReference> Resolve(OrthoDrawingSnapshot drawing);
}
public sealed record OrthoDrawingSnapshot
{
public required string StableId { get; init; }
public IReadOnlyList<OrthoViewSourceSnapshot> Views { get; init; } = Array.Empty<OrthoViewSourceSnapshot>();
}
public sealed record OrthoViewSourceSnapshot
{
public required string ViewStableId { get; init; }
public IReadOnlyList<string> ReferencedDrawingPaths { get; init; } = Array.Empty<string>();
}
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
@@ -210,7 +148,6 @@ public sealed record AnnotationIntent
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<AnnotationOperationPlan> Operations { get; init; } = Array.Empty<AnnotationOperationPlan>();
@@ -6,7 +6,6 @@ namespace PRecAnnot.Core;
public sealed class AnnotationPlanBuilder : IAnnotationPlanBuilder
{
public const int CurrentPlanSchemaVersion = 1;
public AnnotationPlan Build(AnnotationPlanningRequest request)
{
var objects = request.Objects.OrderBy(x => x.SnapshotId, StringComparer.Ordinal).ToArray();
@@ -31,12 +30,6 @@ public sealed class AnnotationPlanBuilder : IAnnotationPlanBuilder
continue;
}
if (item.MembershipStatus is not ViewMembershipStatus.Resolved and not ViewMembershipStatus.PartiallyResolved)
{
operations.Add(new AnnotationOperationPlan { SourceSnapshotId = item.SnapshotId, Kind = AnnotationOperationKind.Skip, Reasons = new[] { "VIEW_MEMBERSHIP_NOT_RESOLVED" } });
continue;
}
var text = string.IsNullOrWhiteSpace(item.LineNumber) ? item.Tag?.Trim() : item.LineNumber!.Trim();
if (string.IsNullOrWhiteSpace(text))
{
@@ -91,8 +84,7 @@ public sealed class AnnotationPlanBuilder : IAnnotationPlanBuilder
return new AnnotationPlan
{
PlanSchemaVersion = CurrentPlanSchemaVersion,
PlanId = BuildPlanId(request, objects, operations),
PlanId = BuildPlanId(request, objects),
CommandName = request.CommandName,
Operations = operations,
Diagnostics = diagnostics,
@@ -100,31 +92,18 @@ public sealed class AnnotationPlanBuilder : IAnnotationPlanBuilder
Create = creates,
Update = updates,
Delete = Array.Empty<string>(),
SkipReasons = operations.Where(x => x.Kind == AnnotationOperationKind.Skip).SelectMany(x => x.Reasons).OrderBy(x => x, StringComparer.Ordinal).ToArray(),
SkipReasons = operations.Where(x => x.Kind == AnnotationOperationKind.Skip).SelectMany(x => x.Reasons).ToArray(),
ExaminedCount = objects.Length,
IsDeterministic = true
};
}
private static string BuildPlanId(AnnotationPlanningRequest request, IReadOnlyList<PlantObjectSnapshot> objects, IReadOnlyList<AnnotationOperationPlan> operations)
private static string BuildPlanId(AnnotationPlanningRequest request, IReadOnlyList<PlantObjectSnapshot> objects)
{
var canonical = new StringBuilder("schema=").Append(CurrentPlanSchemaVersion)
.Append("|command=").Append(Normalize(request.CommandName))
.Append("|source=").Append(Normalize(Path.GetFileName(request.Viewport.SourceDrawingName)))
.Append("|view=").Append(Normalize(request.Viewport.Id));
foreach (var item in objects.OrderBy(x => x.SnapshotId, StringComparer.Ordinal))
{
canonical.Append("|object=").Append(Normalize(item.SnapshotId)).Append('|').Append(Normalize(item.ObjectClass))
.Append('|').Append(Normalize(item.Tag)).Append('|').Append(Normalize(item.LineNumber))
.Append('|').Append(item.MembershipStatus);
foreach (var property in item.Properties.OrderBy(x => x.Key, StringComparer.Ordinal))
canonical.Append("|property=").Append(Normalize(property.Key)).Append('=').Append(Normalize(property.Value));
}
foreach (var operation in operations.OrderBy(x => x.SourceSnapshotId, StringComparer.Ordinal).ThenBy(x => x.Kind))
canonical.Append("|operation=").Append(Normalize(operation.SourceSnapshotId)).Append(':').Append(operation.Kind).Append(':').Append(string.Join(',', operation.Reasons.OrderBy(x => x, StringComparer.Ordinal)));
var canonical = new StringBuilder(request.CommandName).Append('|').Append(request.Viewport.SourceDrawingName).Append('|').Append(request.Viewport.Id);
foreach (var item in objects)
canonical.Append('|').Append(item.SnapshotId).Append('|').Append(item.ObjectClass).Append('|').Append(item.Tag).Append('|').Append(item.LineNumber).Append('|').Append(item.Geometry.PaperPosition);
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(canonical.ToString()));
return "plan-" + Convert.ToHexString(hash)[..24];
}
private static string Normalize(string? value) => (value ?? string.Empty).Trim().Normalize(NormalizationForm.FormC);
}
@@ -12,8 +12,7 @@ public sealed class AnnotationRuleEngine : IAnnotationRuleEngine
ObjectClass = item.ClassName,
Tag = item.Tag,
LineNumber = item.LineNumber,
Geometry = new GeometrySnapshot { PaperPosition = new Point2Dto(item.Position.X, item.Position.Y), Rotation = item.Rotation },
MembershipStatus = ViewMembershipStatus.Resolved
Geometry = new GeometrySnapshot { PaperPosition = new Point2Dto(item.Position.X, item.Position.Y), Rotation = item.Rotation }
}).ToArray();
return new AnnotationPlanBuilder().Build(new AnnotationPlanningRequest
@@ -1,47 +0,0 @@
using System.Security.Cryptography;
using System.Text;
using PRecAnnot.Abstractions;
namespace PRecAnnot.Core;
public sealed class OrthoSourceDrawingResolver : IOrthoSourceDrawingResolver
{
public IReadOnlyList<OrthoSourceDrawingReference> Resolve(OrthoDrawingSnapshot drawing)
{
var candidates = drawing.Views
.OrderBy(x => x.ViewStableId, StringComparer.Ordinal)
.SelectMany(x => x.ReferencedDrawingPaths)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => x.Trim().Replace('\\', '/'))
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
.Select(path => new OrthoSourceDrawingReference
{
StableId = StableId(drawing.StableId, path),
DisplayName = Path.GetFileName(path),
ProjectRelativePath = path,
Status = SourceDrawingResolutionStatus.Resolved,
EvidenceCodes = new[] { "SOURCE_FROM_VIEW_DEFINITION", "SOURCE_PATH_MATCHED_PROJECT_RELATIVE" }
})
.ToArray();
return candidates.Length != 0
? candidates
: new[]
{
new OrthoSourceDrawingReference
{
StableId = StableId(drawing.StableId, "none"),
DisplayName = "source drawing unavailable",
Status = SourceDrawingResolutionStatus.NotReferenced,
EvidenceCodes = new[] { "ORTHO_SOURCE_DRAWING_NOT_RESOLVED" }
}
};
}
private static string StableId(string drawingId, string source)
{
var hash = SHA256.HashData(Encoding.UTF8.GetBytes($"{drawingId}|{source}"));
return "src-" + Convert.ToHexString(hash)[..20];
}
}
@@ -77,11 +77,9 @@ public sealed class EntryPoint : IExtensionApplication
var builder = new AnnotationPlanBuilder();
var plans = new List<AnnotationPlan>();
var objectsByViewport = new List<IReadOnlyList<PlantObjectSnapshot>>();
foreach (var viewport in context.Viewports)
{
var objects = new PlantObjectReader().ReadObjects(viewport, CancellationToken.None);
objectsByViewport.Add(objects);
plans.Add(builder.Build(new AnnotationPlanningRequest { CommandName = commandName, Viewport = viewport, Objects = objects }));
}
@@ -96,16 +94,7 @@ public sealed class EntryPoint : IExtensionApplication
WarningCount = plans.Sum(x => x.Summary.WarningCount),
ErrorCount = plans.Sum(x => x.Summary.ErrorCount)
};
var membershipResolved = objectsByViewport.SelectMany(x => x).Count(x => x.MembershipStatus == ViewMembershipStatus.Resolved);
var membershipPartial = objectsByViewport.SelectMany(x => x).Count(x => x.MembershipStatus == ViewMembershipStatus.PartiallyResolved);
var membershipUnresolved = objectsByViewport.SelectMany(x => x).Count(x => x.MembershipStatus == ViewMembershipStatus.NotResolved);
var planId = plans.Count == 1 ? plans[0].PlanId : null;
details["ObjectsExamined"] = summary.ObjectsExamined;
details["PlanSchemaVersion"] = AnnotationPlanBuilder.CurrentPlanSchemaVersion;
details["PlanId"] = planId;
details["MembershipResolved"] = membershipResolved;
details["MembershipPartial"] = membershipPartial;
details["MembershipUnresolved"] = membershipUnresolved;
details["PlanCreateCount"] = summary.CreateCount;
details["PlanUpdateCount"] = summary.UpdateCount;
details["PlanSkipCount"] = summary.SkipCount;
@@ -114,7 +103,6 @@ public sealed class EntryPoint : IExtensionApplication
details["ErrorCount"] = summary.ErrorCount;
RuntimeDiagnostics.Write("CommandPreflightCompleted", operationId: operationId, commandName: commandName, resultStatus: "DryRunCompleted", document: document, details: details);
WriteEditor(document, $"\nP_Rec_Annot — диагностический план\nПроект: {context.ProjectDisplayName}\nТип чертежа: Ortho\nViewport: {context.Viewports.Count}\nОбъектов найдено: {summary.ObjectsExamined}\nБудет создано: {summary.CreateCount}\nБудет обновлено: {summary.UpdateCount}\nБудет пропущено: {summary.SkipCount}\nКонфликтов: {summary.ConflictCount}\nОшибок: {summary.ErrorCount}\nDWG не изменён.");
WriteEditor(document, $"\nPlan schema: {AnnotationPlanBuilder.CurrentPlanSchemaVersion}; PlanId: {planId ?? "multiple"}; membership resolved/partial/unresolved: {membershipResolved}/{membershipPartial}/{membershipUnresolved}.");
WriteUsage(operationId, commandName, "DryRunCompleted", document, details, stopwatch.ElapsedMilliseconds);
RuntimeDiagnostics.Write("CommandCompleted", operationId: operationId, commandName: commandName, resultStatus: "DryRunCompleted", document: document, details: details);
}
@@ -1,81 +0,0 @@
using System.Collections;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using Autodesk.ProcessPower.Drawings2d;
namespace PRecAnnot.Plant3D2026;
// This is a diagnostic-only probe. It is never part of source resolution and is
// called only by the explicit DryRun/OrthoStructure environment flag combination.
internal static class OrthoRuntimeStructureInspector
{
public static void Inspect(IDwgViewDef view)
{
if (!RuntimeDiagnostics.IsOrthoStructureDiagnosticsEnabled) return;
try
{
var query = view.DwgQuery;
var modelFiles = query?.ModelFiles;
var details = new Dictionary<string, object?>
{
["ViewRuntimeType"] = TypeName(view.GetType()),
["DwgQueryRuntimeType"] = query is null ? null : TypeName(query.GetType()),
["ModelFilesDeclaredType"] = typeof(ModelFile[]).FullName,
["ModelFilesRuntimeType"] = modelFiles?.GetType().AssemblyQualifiedName,
["ModelFilesCount"] = modelFiles?.Length ?? 0,
["ModelFileElements"] = modelFiles?.Select(DescribeModelFile).ToArray() ?? Array.Empty<IReadOnlyDictionary<string, object?>>()
};
RuntimeDiagnostics.Write("OrthoRuntimeStructureInspected", resultStatus: "Captured", details: details);
}
catch (Exception exception)
{
RuntimeDiagnostics.Write("OrthoRuntimeStructureInspectionFailed", "WARNING", resultStatus: "Failed", exception: exception);
}
}
private static IReadOnlyDictionary<string, object?> DescribeModelFile(ModelFile? modelFile)
{
if (modelFile is null)
{
return new Dictionary<string, object?> { ["IsNull"] = true };
}
var properties = modelFile.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(property => property.CanRead && property.GetIndexParameters().Length == 0)
.OrderBy(property => property.Name, StringComparer.Ordinal)
.Select(property => DescribeProperty(modelFile, property))
.ToArray();
return new Dictionary<string, object?>
{
["RuntimeType"] = TypeName(modelFile.GetType()),
["Properties"] = properties
};
}
private static IReadOnlyDictionary<string, object?> DescribeProperty(ModelFile modelFile, PropertyInfo property)
{
object? value;
try { value = property.GetValue(modelFile); }
catch { value = null; }
return new Dictionary<string, object?>
{
["PropertyName"] = property.Name,
["PropertyType"] = property.PropertyType.FullName,
["ValueKind"] = value?.GetType().FullName ?? "null",
["IsNull"] = value is null,
["StringLength"] = value is string text ? text.Length : null,
["PathKind"] = property.Name == "ModelFileName" && value is string path
? (Path.IsPathRooted(path) ? "Absolute" : "ProjectRelative")
: null,
["CollectionCount"] = value is ICollection collection ? collection.Count : null,
["StableHash"] = value is null ? null : Hash(value.ToString() ?? string.Empty)
};
}
private static string TypeName(Type type) => $"{type.FullName}, {type.Assembly.GetName().Name}, {type.Assembly.GetName().Version}";
private static string Hash(string value) => Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(value)))[..16];
}
@@ -14,9 +14,7 @@
<Reference Include="PnPDataObjects"><HintPath>$(AutoCAD2026ManagedDir)\PnPDataObjects.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
<Reference Include="PnPProjectManagerMgd"><HintPath>$(Plant3D2026ManagedDir)\PnPProjectManagerMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
<Reference Include="PnP3dObjectsMgd"><HintPath>$(Plant3D2026ManagedDir)\PnP3dObjectsMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
<Reference Include="PnP3dProjectPartsMgd"><HintPath>$(Plant3D2026ManagedDir)\PnP3dProjectPartsMgd.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
<Reference Include="PnP3dOrthoProjectPart"><HintPath>$(Plant3D2026ManagedDir)\PnP3dOrthoProjectPart.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
<Reference Include="PnPDwg2dDef"><HintPath>$(Plant3D2026ManagedDir)\PnPDwg2dDef.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
<Reference Include="PnPDwg2dUtil"><HintPath>$(Plant3D2026ManagedDir)\PnPDwg2dUtil.dll</HintPath><Private>false</Private><CopyLocal>false</CopyLocal></Reference>
</ItemGroup>
</Project>
@@ -1,9 +1,7 @@
using System.Security.Cryptography;
using System.Text;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.ProcessPower.DataLinks;
using Autodesk.ProcessPower.Drawings2d;
using Autodesk.ProcessPower.P3dProjectParts;
using Autodesk.ProcessPower.PlantInstance;
using Autodesk.ProcessPower.ProjectManager;
@@ -34,9 +32,6 @@ internal sealed class PlantRuntimeContextReader : IPlantRuntimeContextReader
return Empty(true, false, "NO_PLANT_PROJECT", "Активный Plant 3D-проект не найден.");
}
var displayName = string.IsNullOrWhiteSpace(project.Name) ? null : project.Name.Trim();
var projectStatus = displayName is null ? PlantProjectDetectionStatus.FoundWithoutDisplayName : PlantProjectDetectionStatus.FoundWithName;
OrthoProject? orthoProject;
try { orthoProject = PlantApplication.ProjectPart("Ortho") as OrthoProject; }
catch (Exception exception)
@@ -65,10 +60,9 @@ internal sealed class PlantRuntimeContextReader : IPlantRuntimeContextReader
HasPlantProject = true,
IsOrthoDrawing = true,
DrawingName = Path.GetFileName(document.Name),
ProjectDisplayName = displayName ?? "display name unavailable",
ProjectDetectionStatus = projectStatus,
ProjectDisplayName = project.Name,
Viewports = viewports,
Diagnostics = displayName is null ? new[] { new RuntimeDiagnostic { Code = "PLANT_PROJECT_DISPLAY_NAME_EMPTY", Message = "Plant project is open but no display name is available.", Severity = "Warning" } } : Array.Empty<RuntimeDiagnostic>(),
Diagnostics = Array.Empty<RuntimeDiagnostic>(),
Detection = new OrthoDetectionResult
{
Status = OrthoDetectionStatus.Confirmed,
@@ -88,8 +82,6 @@ internal sealed class PlantRuntimeContextReader : IPlantRuntimeContextReader
HasActiveDocument = hasDocument,
HasPlantProject = hasProject,
IsOrthoDrawing = false,
ProjectDisplayName = hasProject ? "display name unavailable" : null,
ProjectDetectionStatus = hasProject ? PlantProjectDetectionStatus.Ambiguous : PlantProjectDetectionStatus.NotFound,
Diagnostics = new[] { new RuntimeDiagnostic { Code = code, Message = message } },
Detection = new OrthoDetectionResult { Status = status, Evidence = evidence, Diagnostics = new[] { new RuntimeDiagnostic { Code = code, Message = message } } }
};
@@ -132,7 +124,7 @@ internal sealed class PlantOrthoViewportReader : IOrthoViewportReader
TwistAngle = 0,
IsOn = true,
IsLocked = false,
SourceDrawingName = ReadSourceDrawingPath(view),
SourceDrawingName = sheet.DwgName,
ViewName = view.ViewName
});
}
@@ -151,229 +143,52 @@ internal sealed class PlantOrthoViewportReader : IOrthoViewportReader
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(sheetId + "|" + viewName));
return "vp-" + Convert.ToHexString(hash)[..20];
}
private static string? ReadSourceDrawingPath(IDwgViewDef view)
{
// Confirmed Plant 3D 2026 contract (PnPDwg2dDef/PnPDwg2dUtil):
// IDwgViewDef.DwgQuery -> IDwgQuery.ModelFiles -> ModelFile.ModelFileName.
// The Ortho sheet is never used as a Piping DataLinks source.
try
{
if (!OrthoModelFilesContract.IsSupported(view, out var diagnostic))
{
RuntimeDiagnostics.Write("OrthoModelFilesContractRejected", "WARNING", resultStatus: diagnostic.Code, details: diagnostic.Details);
return null;
}
if (RuntimeDiagnostics.IsOrthoStructureDiagnosticsEnabled)
{
OrthoRuntimeStructureInspector.Inspect(view);
}
return view.DwgQuery?.ModelFiles
.Select(file => file.ModelFileName)
.FirstOrDefault(value => !string.IsNullOrWhiteSpace(value));
}
catch (Exception exception)
{
RuntimeDiagnostics.Write("OrthoModelFilesReadFailed", "WARNING", resultStatus: "ORTHO_MODEL_FILES_API_UNSUPPORTED", exception: exception);
}
return null;
}
}
internal static class OrthoModelFilesContract
{
private const string ExpectedViewType = "Autodesk.ProcessPower.Drawings2d.DwgViewDef";
private const string ExpectedQueryType = "Autodesk.ProcessPower.Drawings2d.DwgQueryByBox";
private const string ExpectedModelFileType = "Autodesk.ProcessPower.Drawings2d.ModelFile";
private const string ExpectedDefAssembly = "PnPDwg2dDef";
private const string ExpectedUtilAssembly = "PnPDwg2dUtil";
private const string ExpectedVersion = "0.0.0.0";
public static bool IsSupported(IDwgViewDef view, out OrthoModelFilesContractDiagnostic diagnostic)
{
var query = view.DwgQuery;
var files = query?.ModelFiles;
var valid = HasExpectedType(view, ExpectedViewType, ExpectedDefAssembly) &&
query is not null && HasExpectedType(query, ExpectedQueryType, ExpectedDefAssembly) &&
files is not null && files.GetType() == typeof(ModelFile[]) &&
files.All(file => file is not null && HasExpectedType(file, ExpectedModelFileType, ExpectedUtilAssembly));
diagnostic = new OrthoModelFilesContractDiagnostic(
valid ? "ORTHO_MODEL_FILES_API_SUPPORTED" : "ORTHO_MODEL_FILES_API_UNSUPPORTED",
new Dictionary<string, object?>
{
["ExpectedViewType"] = ExpectedViewType,
["ActualViewType"] = TypeName(view),
["ExpectedQueryType"] = ExpectedQueryType,
["ActualQueryType"] = query is null ? null : TypeName(query),
["ExpectedModelFileType"] = ExpectedModelFileType,
["ActualModelFilesType"] = files?.GetType().AssemblyQualifiedName,
["ExpectedAssemblyVersion"] = ExpectedVersion,
["ActualViewAssemblyVersion"] = view.GetType().Assembly.GetName().Version?.ToString(),
["ActualQueryAssemblyVersion"] = query?.GetType().Assembly.GetName().Version?.ToString(),
["ActualModelFilesAssemblyVersion"] = files?.GetType().Assembly.GetName().Version?.ToString()
});
return valid;
}
private static bool HasExpectedType(object value, string expectedType, string expectedAssembly) =>
string.Equals(value.GetType().FullName, expectedType, StringComparison.Ordinal) &&
string.Equals(value.GetType().Assembly.GetName().Name, expectedAssembly, StringComparison.Ordinal) &&
string.Equals(value.GetType().Assembly.GetName().Version?.ToString(), ExpectedVersion, StringComparison.Ordinal);
private static string TypeName(object value) => $"{value.GetType().FullName}, {value.GetType().Assembly.GetName().Name}, {value.GetType().Assembly.GetName().Version}";
}
internal sealed record OrthoModelFilesContractDiagnostic(string Code, IReadOnlyDictionary<string, object?> Details);
internal sealed class PlantObjectReader : IPlantObjectReader
{
public IReadOnlyList<PlantObjectSnapshot> ReadObjects(OrthoViewportInfo viewport, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(viewport.SourceDrawingName))
{
WriteOutcome("ORTHO_SOURCE_DRAWING_NOT_RESOLVED", viewport);
return Array.Empty<PlantObjectSnapshot>();
}
PipingProject? pipingProject;
try { pipingProject = PlantApplication.ProjectPart("Piping") as PipingProject; }
catch (Exception exception)
{
WriteOutcome("PIPING_PROJECT_PART_NOT_FOUND", viewport, exception);
return Array.Empty<PlantObjectSnapshot>();
}
if (pipingProject is null)
{
WriteOutcome("PIPING_PROJECT_PART_NOT_FOUND", viewport);
return Array.Empty<PlantObjectSnapshot>();
}
var sourceDrawing = ResolveProjectDrawing(pipingProject, viewport.SourceDrawingName);
if (sourceDrawing is null) return Array.Empty<PlantObjectSnapshot>();
var document = AcadApplication.DocumentManager.MdiActiveDocument;
if (document is null) return Array.Empty<PlantObjectSnapshot>();
DataLinksManager? dataLinks;
try { dataLinks = pipingProject.DataLinksManager; }
catch (Exception exception)
{
WriteOutcome("SOURCE_DATALINKS_UNAVAILABLE", viewport, exception);
return Array.Empty<PlantObjectSnapshot>();
}
if (dataLinks is null)
{
WriteOutcome("SOURCE_DATALINKS_UNAVAILABLE", viewport);
return Array.Empty<PlantObjectSnapshot>();
}
try { dataLinks = PlantApplication.ProjectPart("Piping")?.DataLinksManager; }
catch { return Array.Empty<PlantObjectSnapshot>(); }
if (dataLinks is null) return Array.Empty<PlantObjectSnapshot>();
var snapshots = new List<PlantObjectSnapshot>();
try
foreach (var rowId in dataLinks.SelectAcPpRowIds(document.Database))
{
// Confirmed Plant 3D 2026 contract: resolve the source model to the
// Piping project drawing record, then read its DataLinks by drawing Id.
// The active Ortho database is deliberately never passed to DataLinks.
var rowIds = dataLinks.SelectAcPpRowIds(sourceDrawing.Id);
if (rowIds.Count == 0)
try
{
WriteOutcome("SOURCE_DATALINKS_NO_ROWS", viewport, details: new Dictionary<string, object?> { ["ProjectDrawingResolved"] = true });
return Array.Empty<PlantObjectSnapshot>();
cancellationToken.ThrowIfCancellationRequested();
var className = dataLinks.GetObjectClassname(rowId);
var properties = dataLinks.GetAllProperties(rowId, true)
.GroupBy(x => x.Key, StringComparer.OrdinalIgnoreCase)
.ToDictionary(x => x.Key, x => x.Last().Value, StringComparer.OrdinalIgnoreCase);
string? Value(params string[] names) => properties.FirstOrDefault(x => names.Any(name => string.Equals(name, x.Key, StringComparison.OrdinalIgnoreCase))).Value;
snapshots.Add(new PlantObjectSnapshot
{
SnapshotId = StableId(Path.GetFileName(document.Name), rowId, className),
ObjectClass = className ?? string.Empty,
Tag = Value("Tag", "TAG"),
LineNumber = Value("Line Number", "LineNumber", "LINENUMBER"),
SupportNumber = Value("Support Number", "SupportNumber"),
EquipmentNumber = Value("Equipment Number", "EquipmentNumber"),
Geometry = new GeometrySnapshot(),
Properties = properties.ToDictionary(x => x.Key, x => (string?)x.Value, StringComparer.OrdinalIgnoreCase),
Diagnostics = new[] { "GEOMETRY_NOT_MAPPED" }
});
}
foreach (var rowId in rowIds)
catch
{
try
{
cancellationToken.ThrowIfCancellationRequested();
var className = dataLinks.GetObjectClassname(rowId);
var properties = dataLinks.GetAllProperties(rowId, true)
.GroupBy(x => x.Key, StringComparer.OrdinalIgnoreCase)
.ToDictionary(x => x.Key, x => x.Last().Value, StringComparer.OrdinalIgnoreCase);
string? Value(params string[] names) => properties.FirstOrDefault(x => names.Any(name => string.Equals(name, x.Key, StringComparison.OrdinalIgnoreCase))).Value;
snapshots.Add(new PlantObjectSnapshot
{
SnapshotId = StableId(viewport.SourceDrawingName, rowId, className),
ObjectClass = className ?? string.Empty,
Tag = Value("Tag", "TAG"),
LineNumber = Value("Line Number", "LineNumber", "LINENUMBER"),
SupportNumber = Value("Support Number", "SupportNumber"),
EquipmentNumber = Value("Equipment Number", "EquipmentNumber"),
Geometry = new GeometrySnapshot(),
Properties = properties.ToDictionary(x => x.Key, x => (string?)x.Value, StringComparer.OrdinalIgnoreCase),
Diagnostics = new[] { "GEOMETRY_NOT_MAPPED" }
});
}
catch (Exception exception)
{
RuntimeDiagnostics.Write("SourceDataLinksRowReadFailed", "WARNING", resultStatus: "SOURCE_DATABASE_READ_FAILED", exception: exception);
}
// Keep the read path best-effort; no write operation is attempted.
}
}
catch (DLException exception)
{
WriteOutcome("SOURCE_DATALINKS_UNAVAILABLE", viewport, exception);
}
catch (Exception exception)
{
WriteOutcome("SOURCE_DATABASE_READ_FAILED", viewport, exception);
}
WriteOutcome(snapshots.Count == 0 ? "SOURCE_PIPE_ROWS_NOT_FOUND" : "SOURCE_DATALINKS_READ", viewport,
details: new Dictionary<string, object?> { ["SourcePlantObjectsRead"] = snapshots.Count, ["PipeObjectsRead"] = snapshots.Count });
return snapshots.OrderBy(x => x.SnapshotId, StringComparer.Ordinal).ToArray();
}
private static PnPProjectDrawing? ResolveProjectDrawing(PipingProject pipingProject, string sourceDrawingPath)
{
if (!Path.IsPathRooted(sourceDrawingPath))
{
WriteOutcome("ORTHO_SOURCE_DRAWING_NOT_IN_PROJECT", null);
return null;
}
string normalizedSource;
try { normalizedSource = Path.GetFullPath(sourceDrawingPath); }
catch (Exception exception)
{
WriteOutcome("ORTHO_SOURCE_DRAWING_NOT_RESOLVED", null, exception);
return null;
}
var matches = pipingProject.GetPnPDrawingFiles()
.Where(drawing => MatchesSourcePath(drawing, normalizedSource))
.OrderBy(drawing => drawing.Id)
.ToArray();
if (matches.Length == 1)
{
RuntimeDiagnostics.Write("SourceProjectDrawingResolved", resultStatus: "SOURCE_FROM_PROJECT_DRAWING_ROW", details: new Dictionary<string, object?> { ["ProjectDrawingResolved"] = true });
return matches[0];
}
WriteOutcome(matches.Length == 0 ? "ORTHO_SOURCE_DRAWING_NOT_IN_PROJECT" : "ORTHO_SOURCE_DRAWING_AMBIGUOUS", null,
details: new Dictionary<string, object?> { ["CandidateCount"] = matches.Length });
return null;
}
private static bool MatchesSourcePath(PnPProjectDrawing drawing, string normalizedSource) =>
EquivalentPath(drawing.AbsoluteFileName, normalizedSource) ||
EquivalentPath(drawing.ResolvedFilePath, normalizedSource);
private static bool EquivalentPath(string? candidate, string normalizedSource)
{
if (string.IsNullOrWhiteSpace(candidate)) return false;
try { return string.Equals(Path.GetFullPath(candidate), normalizedSource, StringComparison.OrdinalIgnoreCase); }
catch { return false; }
}
private static void WriteOutcome(string code, OrthoViewportInfo? viewport, Exception? exception = null, IReadOnlyDictionary<string, object?>? details = null)
{
var sanitizedDetails = new Dictionary<string, object?>
{
["SourceResolved"] = viewport?.SourceDrawingName is not null
};
if (details is not null) foreach (var detail in details) sanitizedDetails[detail.Key] = detail.Value;
RuntimeDiagnostics.Write("SourceDataLinksReadCompleted", code == "SOURCE_DATALINKS_READ" ? "INFO" : "WARNING", resultStatus: code, exception: exception, details: sanitizedDetails);
}
private static string StableId(string drawingName, int rowId, string? className)
{
var hash = SHA256.HashData(Encoding.UTF8.GetBytes($"{drawingName}|{rowId}|{className}"));
@@ -14,10 +14,6 @@ internal static class RuntimeDiagnostics
public static string RuntimeMode => Environment.GetEnvironmentVariable("P_REC_ANNOT_RUNTIME_MODE") ?? "Normal";
public static bool IsOrthoStructureDiagnosticsEnabled =>
string.Equals(RuntimeMode, "DryRun", StringComparison.OrdinalIgnoreCase) &&
string.Equals(Environment.GetEnvironmentVariable("P_REC_ANNOT_DIAGNOSTICS"), "OrthoStructure", StringComparison.OrdinalIgnoreCase);
public static void Write(
string eventType,
string level = "INFO",
@@ -104,37 +104,6 @@ public sealed class FoundationTests
Assert.Equal(first.Operations.Select(x => x.SourceSnapshotId), second.Operations.Select(x => x.SourceSnapshotId));
}
[Fact] public void AnnotationPlan_ReversedObjectOrder_HasSamePlanId()
{
var first = Build(Snapshot("a", "Pipe", "L-1"), Snapshot("b", "Pipe", "L-2"));
var second = Build(Snapshot("b", "Pipe", "L-2"), Snapshot("a", "Pipe", "L-1"));
Assert.Equal(first.PlanId, second.PlanId);
Assert.Equal(first.Summary, second.Summary);
}
[Fact] public void AnnotationPlan_AbsolutePath_DoesNotAffectPlanId()
{
var builder = new AnnotationPlanBuilder();
var item = Snapshot("a", "Pipe", "L-1");
var first = builder.Build(new AnnotationPlanningRequest { CommandName = "PHP_REC_ANNOT", Viewport = new OrthoViewportInfo { Id = "v", DisplayName = "v", SourceDrawingName = "C:\\one\\model.dwg" }, Objects = new[] { item } });
var second = builder.Build(new AnnotationPlanningRequest { CommandName = "PHP_REC_ANNOT", Viewport = new OrthoViewportInfo { Id = "v", DisplayName = "v", SourceDrawingName = "D:\\two\\model.dwg" }, Objects = new[] { item } });
Assert.Equal(first.PlanId, second.PlanId);
}
[Fact] public void AnnotationPlan_ChangedRelevantProperty_ChangesPlanId()
{
var first = Build(Snapshot("a", "Pipe", "L-1"));
var second = Build(Snapshot("a", "Pipe", "L-2"));
Assert.NotEqual(first.PlanId, second.PlanId);
}
[Fact] public void AnnotationPlan_UnresolvedMembership_IsStableSkip()
{
var plan = Build(new PlantObjectSnapshot { SnapshotId = "a", ObjectClass = "Pipe", LineNumber = "L-1", Geometry = new GeometrySnapshot(), MembershipStatus = ViewMembershipStatus.NotResolved });
Assert.Equal(AnnotationOperationKind.Skip, Assert.Single(plan.Operations).Kind);
Assert.Contains("VIEW_MEMBERSHIP_NOT_RESOLVED", plan.SkipReasons);
}
[Fact] public void AnnotationPlan_MissingLineNumber_IsSkipped()
{
var plan = Build(Snapshot("a", "Pipe", null, null));
@@ -161,85 +130,6 @@ public sealed class FoundationTests
Assert.Equal(AnnotationOperationKind.Conflict, plan.Operations.Last().Kind);
}
[Fact] public void OrthoSourceResolver_OneView_ResolvesOneModelDrawing()
{
var result = new OrthoSourceDrawingResolver().Resolve(new OrthoDrawingSnapshot
{
StableId = "sheet",
Views = new[] { new OrthoViewSourceSnapshot { ViewStableId = "view", ReferencedDrawingPaths = new[] { "Plant 3D Models/TestPipeModel.dwg" } } }
});
var source = Assert.Single(result);
Assert.Equal(SourceDrawingResolutionStatus.Resolved, source.Status);
Assert.Equal("TestPipeModel.dwg", source.DisplayName);
}
[Fact] public void OrthoSourceResolver_DuplicateViews_DeduplicatesSource()
{
var result = new OrthoSourceDrawingResolver().Resolve(new OrthoDrawingSnapshot
{
StableId = "sheet",
Views = new[]
{
new OrthoViewSourceSnapshot { ViewStableId = "a", ReferencedDrawingPaths = new[] { "models/A.dwg" } },
new OrthoViewSourceSnapshot { ViewStableId = "b", ReferencedDrawingPaths = new[] { "models/A.dwg" } }
}
});
Assert.Single(result);
}
[Fact] public void OrthoSourceResolver_MissingSource_ReturnsDiagnostic()
{
var result = new OrthoSourceDrawingResolver().Resolve(new OrthoDrawingSnapshot { StableId = "sheet" });
var source = Assert.Single(result);
Assert.Equal(SourceDrawingResolutionStatus.NotReferenced, source.Status);
Assert.Contains("ORTHO_SOURCE_DRAWING_NOT_RESOLVED", source.EvidenceCodes);
}
[Fact] public void DwgQueryContract_UsesConfirmedModelFileContract()
{
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "PlantReadPath.cs"));
Assert.Contains("view.DwgQuery?.ModelFiles", source);
Assert.Contains("file.ModelFileName", source);
Assert.Contains("ORTHO_MODEL_FILES_API_UNSUPPORTED", source);
}
[Fact] public void DwgQueryContract_DoesNotGuessAlternativePropertyNames()
{
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "PlantReadPath.cs"));
Assert.DoesNotContain("GetProperty(\"ModelFileName\")", source);
Assert.DoesNotContain("GetProperty(\"Value\")", source);
Assert.DoesNotContain("GetProperty(\"FileName\")", source);
}
[Fact] public void OrthoSourceReader_UsesResolvedPipingProjectDrawingId()
{
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "PlantReadPath.cs"));
Assert.Contains("pipingProject.GetPnPDrawingFiles()", source);
Assert.Contains("dataLinks.SelectAcPpRowIds(sourceDrawing.Id)", source);
}
[Fact] public void OrthoSourceReader_DoesNotQueryTheActiveOrthoDatabase()
{
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "PlantReadPath.cs"));
Assert.DoesNotContain("SelectAcPpRowIds(sourceDatabase)", source);
Assert.DoesNotContain("ReadDwgFile(viewport.SourceDrawingName", source);
}
[Fact] public void OrthoSourceReader_ReportsDistinctSourceDiagnostics()
{
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "PlantReadPath.cs"));
Assert.Contains("ORTHO_SOURCE_DRAWING_NOT_IN_PROJECT", source);
Assert.Contains("SOURCE_DATALINKS_UNAVAILABLE", source);
Assert.Contains("SOURCE_DATALINKS_NO_ROWS", source);
}
[Fact] public void RuntimeInspector_IsDisabledByDefault()
{
var source = File.ReadAllText(Path.Combine(ProjectRoot, "src", "PRecAnnot.Plant3D2026", "RuntimeDiagnostics.cs"));
Assert.Contains("P_REC_ANNOT_DIAGNOSTICS", source);
Assert.Contains("OrthoStructure", source);
}
[Fact] public void ApplyMode_IsBlocked() => Assert.Throws<InvalidOperationException>(() => new ExecutionModeWriteGuard(PRecAnnotExecutionMode.Apply).EnsureWriteAllowed("test"));
[Fact] public void DryRunPath_HasNoForWriteOperations()
@@ -252,5 +142,5 @@ public sealed class FoundationTests
}
private static AnnotationPlan Build(params PlantObjectSnapshot[] objects) => new AnnotationPlanBuilder().Build(new AnnotationPlanningRequest { CommandName = "PHP_REC_ANNOT", Viewport = new OrthoViewportInfo { Id = "vp", DisplayName = "A", SourceDrawingName = "test.dwg" }, Objects = objects });
private static PlantObjectSnapshot Snapshot(string id, string type, string? line, string? tag = "TAG") => new() { SnapshotId = id, ObjectClass = type, LineNumber = line, Tag = tag, Geometry = new GeometrySnapshot { PaperPosition = new Point2Dto(1, 2) }, MembershipStatus = ViewMembershipStatus.Resolved };
private static PlantObjectSnapshot Snapshot(string id, string type, string? line, string? tag = "TAG") => new() { SnapshotId = id, ObjectClass = type, LineNumber = line, Tag = tag, Geometry = new GeometrySnapshot { PaperPosition = new Point2Dto(1, 2) } };
}
@@ -0,0 +1,84 @@
param(
[string]$DeployedRoot = '\\phpsrv03\NBIM\save\Apps\Plant3D\DriveA\P_Rec_Annot',
[string]$SourceRoot = '\\phpsrv03\NBIM\code\CS\P_Rec_Annot\v1.0.4\repo',
[string]$OutputRoot = (Split-Path -Parent $PSCommandPath)
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Get-PeArchitecture([string]$Path) {
if ([IO.Path]::GetExtension($Path) -notin '.dll', '.exe') { return $null }
try {
$stream = [IO.File]::Open($Path, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::ReadWrite)
try {
$reader = [IO.BinaryReader]::new($stream)
$stream.Position = 0x3c; $offset = $reader.ReadInt32(); $stream.Position = $offset + 4
$machine = $reader.ReadUInt16()
switch ($machine) { 0x14c { 'x86' } 0x8664 { 'x64' } 0x1c4 { 'ARM' } default { 'Unknown' } }
} finally { $stream.Dispose() }
} catch { 'Unreadable' }
}
function Get-AssemblyMetadata([string]$Path) {
$result = [ordered]@{ AssemblyName = $null; AssemblyVersion = $null; TargetFramework = $null }
if ([IO.Path]::GetExtension($Path) -ne '.dll') { return [pscustomobject]$result }
try {
$name = [Reflection.AssemblyName]::GetAssemblyName($Path)
$result.AssemblyName = $name.Name; $result.AssemblyVersion = $name.Version.ToString()
try {
$assembly = [Reflection.Assembly]::ReflectionOnlyLoadFrom($Path)
$attribute = $assembly.GetCustomAttributesData() | Where-Object { $_.AttributeType.FullName -eq 'System.Runtime.Versioning.TargetFrameworkAttribute' } | Select-Object -First 1
if ($attribute) { $result.TargetFramework = [string]$attribute.ConstructorArguments[0].Value }
} catch { }
} catch { }
[pscustomobject]$result
}
$inventory = foreach ($file in Get-ChildItem -LiteralPath $DeployedRoot -Recurse -File) {
$hash = Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256
$version = try { [Diagnostics.FileVersionInfo]::GetVersionInfo($file.FullName) } catch { $null }
$meta = Get-AssemblyMetadata $file.FullName
[pscustomobject]@{
RelativePath = $file.FullName.Substring($DeployedRoot.Length).TrimStart('\')
Name = $file.Name; Extension = $file.Extension; Length = $file.Length; LastWriteTimeUtc = $file.LastWriteTimeUtc.ToString('o')
Sha256 = $hash.Hash; FileVersion = $version.FileVersion; ProductVersion = $version.ProductVersion
AssemblyName = $meta.AssemblyName; AssemblyVersion = $meta.AssemblyVersion; TargetFramework = $meta.TargetFramework
PeArchitecture = Get-PeArchitecture $file.FullName
}
}
$inventory | Sort-Object RelativePath | Export-Csv -LiteralPath (Join-Path $OutputRoot 'deployed-files.csv') -NoTypeInformation -Encoding utf8
$settings = [xml](Get-Content -LiteralPath (Join-Path $DeployedRoot 'Settings.xml'))
$sequence = 0
$configuration = foreach ($item in $settings.Main.LoadAssemblies.LoadAssembly) {
$sequence++
$configured = [string]$item.assemblyname; $resolved = Join-Path $DeployedRoot $configured
$entry = $inventory | Where-Object Name -eq $configured | Select-Object -First 1
[pscustomobject]@{
Sequence = $sequence; ConfigFile = 'Settings.xml'; ConfiguredPath = $configured; ResolvedPath = ('<deployed-root>\' + $configured)
Assembly = $entry.AssemblyName; Exists = Test-Path -LiteralPath $resolved; Sha256 = $entry.Sha256
LoadMethod = 'acDoc.Editor.Command("._netload", fullPath)'; Required = $true
FailureBehavior = 'Outer loader catch stops remaining sequence and shows MessageBox'; Notes = 'Path is combined with OrthoLoader assembly directory.'
}
}
$configuration | Export-Csv -LiteralPath (Join-Path $OutputRoot 'configuration-map.csv') -NoTypeInformation -Encoding utf8
$projects = Get-ChildItem -LiteralPath $SourceRoot -Recurse -File -Filter *.csproj | ForEach-Object {
$content = Get-Content -LiteralPath $_.FullName -Raw
$assemblyName = if ($content -match '<AssemblyName>([^<]+)</AssemblyName>') { $Matches[1] } else { [IO.Path]::GetFileNameWithoutExtension($_.Name) }
$framework = if ($content -match '<TargetFrameworkVersion>([^<]+)</TargetFrameworkVersion>') { $Matches[1] } else { $null }
$platform = if ($content -match '<PlatformTarget>([^<]+)</PlatformTarget>') { $Matches[1] } else { $null }
[pscustomobject]@{ AssemblyName = $assemblyName; Csproj = $_.FullName.Substring($SourceRoot.Length).TrimStart('\'); TargetFramework = $framework; PlatformTarget = $platform }
}
$sourceMap = foreach ($dll in $inventory | Where-Object Extension -eq '.dll') {
$matches = @($projects | Where-Object { $_.AssemblyName -eq $dll.AssemblyName -or $_.AssemblyName -eq [IO.Path]::GetFileNameWithoutExtension($dll.Name) })
$releaseCandidate = Join-Path (Join-Path $SourceRoot 'FilesRelease') $dll.Name
$exactReleaseMatch = (Test-Path -LiteralPath $releaseCandidate) -and ((Get-FileHash -LiteralPath $releaseCandidate -Algorithm SHA256).Hash -eq $dll.Sha256)
$status = if ($exactReleaseMatch) { 'EXACT_SOURCE_MATCH' } elseif ($matches.Count -eq 1) { 'LIKELY_SOURCE_MATCH' } elseif ($matches.Count -gt 1) { 'MULTIPLE_CANDIDATES' } elseif ($dll.Name -match '^PnP|^Ac') { 'AUTODESK_DEPENDENCY' } else { 'NO_SOURCE_FOUND' }
$project = $matches | Select-Object -First 1
[pscustomobject]@{ DeployedDll=$dll.Name; DeployedSha256=$dll.Sha256; FileVersion=$dll.FileVersion; AssemblyVersion=$dll.AssemblyVersion; LegacyProject=if($project){[IO.Path]::GetFileNameWithoutExtension($project.Csproj)}else{$null}; LegacyCsproj=if($project){$project.Csproj}else{$null}; LegacyOutputName=if($project){$project.AssemblyName}else{$null}; TargetFramework=if($project){$project.TargetFramework}else{$null}; PlatformTarget=if($project){$project.PlatformTarget}else{$null}; CommandCount=$null; RibbonRole=if($dll.AssemblyName -eq 'OrthoLoader'){'Central ribbon/loader'}else{$null}; ConfigurationSource=if($configuration.ConfiguredPath -contains $dll.Name){'Settings.xml'}else{$null}; MatchStatus=$status }
}
$sourceMap | Sort-Object DeployedDll | Export-Csv -LiteralPath (Join-Path $OutputRoot 'deployed-to-source-map.csv') -NoTypeInformation -Encoding utf8
"GeneratedUtc=$([DateTime]::UtcNow.ToString('o'))`nDeployedRoot=<network root redacted to report context>`nSourceRoot=<network source root redacted to report context>`nFiles=$($inventory.Count)" | Set-Content -LiteralPath (Join-Path $OutputRoot 'evidence\generation.txt') -Encoding utf8
@@ -0,0 +1,19 @@
# Legacy P_Rec_Annot loading audit
Scope: read-only inspection of the deployed network directory and the v1.0.4 source checkout. No legacy DLL was executed, copied, or deployed.
The deployed root has 52 files, including 22 managed DLLs. `Settings.xml` enumerates 20 application modules. The inventory and its SHA-256 values are in `deployed-files.csv`; generated report paths use `<deployed-root>` rather than embedding a new runtime configuration path.
High-confidence conclusion: the central loader is `OrthoLoader.dll`. `OrthoLoader.Ribbon.Initialize()` invokes `OrthoLoader.Initialize()`. The latter reads adjacent `Settings.xml` and calls `acDoc.Editor.Command("._netload", fullPath)` sequentially for the configured modules. The bootstrap that initially loads `OrthoLoader.dll` is not present in either audited directory; it remains unknown. Therefore the audit proves same-directory loading, but cannot prove whether an external launcher first NETLOADed the UNC copy or a local copy.
Source-to-binary mapping is `EXACT_SOURCE_MATCH` for 15 deployed DLLs by SHA-256 against `FilesRelease`. Six newer deployed DLLs are `LIKELY_SOURCE_MATCH` by assembly/project identity and metadata but differ byte-for-byte from the checked-in release output. `InsertElevation.dll` is `MULTIPLE_CANDIDATES` because archival projects share the assembly identity.
## Potential test data
| RelativePath | Type | LikelyPurpose | ContainsProjectData | SafeForTest | Reason |
|---|---|---|---|---|---|
| `Template.dwg` | DWG | legacy command template | Unknown | No | Located beside production deployment; no authorization to open or copy it was established. |
| `test.txt` | text | unknown/empty marker | No content | Not useful | Zero bytes. |
| `Справка*.pdf/docx` | documentation | user instructions | Unknown | Review only | Not a CAD fixture. |
No `Project.xml`, `.dcf`, or explicitly labelled sample/demo Ortho DWG was found in the deployed root.
@@ -0,0 +1,21 @@
"Sequence","ConfigFile","ConfiguredPath","ResolvedPath","Assembly","Exists","Sha256","LoadMethod","Required","FailureBehavior","Notes"
"1","Settings.xml","AnnotateLineNumbers.dll","<deployed-root>\AnnotateLineNumbers.dll","AnnotateLineNumbers","True","799BC277ED98BD870F01824180B5A945B24F016DFD9956A8CCC630AFE80FDFA4","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"2","Settings.xml","AutoAnnotateView.dll","<deployed-root>\AutoAnnotateView.dll","AutoAnnotateView","True","EAE55411EC84AC747A3816EE65CD095648282BE44235351E7C9ED1C188BCB611","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"3","Settings.xml","AutoLinenumberConnections.dll","<deployed-root>\AutoLinenumberConnections.dll","AutoLinenumberConnections","True","0F6B2A759F2A63B9152B480B6968BDA20F42AD1D922F67CA6E6BFD31A0715F35","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"4","Settings.xml","CheckOrthoView.dll","<deployed-root>\CheckOrthoView.dll","CheckOrthoView","True","89DB5E537C2BAEC292CDD8A0A43819119850119D54958E8CC3C43E2136AB24A0","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"5","Settings.xml","EnablerLoader.dll","<deployed-root>\EnablerLoader.dll","EnablerLoader","True","745D625C27F92842F2EFF3C515DB48BB9FC0FE59B6E4559ACD696BCC93FF4C51","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"6","Settings.xml","ExtentsIntersect.dll","<deployed-root>\ExtentsIntersect.dll","ExtentsIntersect","True","59D2776E083D4BE2FBFBE4F43009EAA9CE0E81A1752815B45C510F80654169D9","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"7","Settings.xml","GetComponentGeometry.dll","<deployed-root>\GetComponentGeometry.dll","GetComponentGeometry","True","9EA8C48FEC4D36D32CC6AC88B78C434662C16D4484F86EFAA46ECC309E9F9142","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"8","Settings.xml","GetLinenumberAnnotationText.dll","<deployed-root>\GetLinenumberAnnotationText.dll","GetLinenumberAnnotationText","True","047E721DBE380061D9ABDD92BC5475440E3B7ADB2BD0F544D538BA24B121D30E","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"9","Settings.xml","GetPlantScriptFolderPath.dll","<deployed-root>\GetPlantScriptFolderPath.dll","GetPlantScriptFolderPath","True","5080A167A1DAF6C19BE08F6CAB678D490736B5E07E121A918A2915F0D9D8BF65","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"10","Settings.xml","GetScriptParameters.dll","<deployed-root>\GetScriptParameters.dll","GetScriptParameters","True","7FF7B0D26BE8D89FF4A5A4FA1C6EC17BDA1506BCCB78AFE0E650137CD7BA5E87","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"11","Settings.xml","InsertElevation.dll","<deployed-root>\InsertElevation.dll","InsertElevation","True","B2D8B98F353D3DDF3A75A848E6922DC30478A1E5F98B372F24A049690492CA82","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"12","Settings.xml","LoadedAssemblies.dll","<deployed-root>\LoadedAssemblies.dll","LoadedAssemblies","True","277EB83C587A984DC2F558B8A7C86AA98E195A77AFA6FADD7DB83F2B801C0E4E","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"13","Settings.xml","OrthoAutoAnnotate.dll","<deployed-root>\OrthoAutoAnnotate.dll","OrthoAutoAnnotate","True","2E6BB2EBA0A98AA3550DFA4E661832FC7C3EE3DFF49BFC147BD4DFAD7A8596C6","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"14","Settings.xml","P3DCopyMissingObjectsToOrthoDrawing.dll","<deployed-root>\P3DCopyMissingObjectsToOrthoDrawing.dll","P3DCopyMissingObjectsToOrthoDrawing","True","6C879AFC7F35EC25E5E2FFF9FF0EE6EFEB155670DBFD5D0CDE9A0F629C5727B2","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"15","Settings.xml","P3DNewMa.dll","<deployed-root>\P3DNewMa.dll","P3DNewMa","True","97246EE9B24FD373551EF380C5AC0CA78CF7ED6A92581D5331B54445A2A948F8","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"16","Settings.xml","P3DSetLayerForViewport.dll","<deployed-root>\P3DSetLayerForViewport.dll","P3DSetLayerForViewport","True","A28E58FDE4EBAA26450CA646C5A85F98C1A04AA42C0BFC5413D718243ACBF42B","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"17","Settings.xml","PHPAnnotations.dll","<deployed-root>\PHPAnnotations.dll","PHPAnnotations","True","816A693F1B775C5506043DD0461055F248D3897E96AC8285DAE29C5B71FFCA73","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"18","Settings.xml","SwapAttributesMenuItem.dll","<deployed-root>\SwapAttributesMenuItem.dll","SwapAttributesMenuItem","True","674C865E34F9C877561E03E2077F7F2C6852C3C8B6A0503ACAA7619F3E80A460","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"19","Settings.xml","UpdateOrthoDrawings.dll","<deployed-root>\UpdateOrthoDrawings.dll","UpdateOrthoDrawings","True","1492FFF1F56853DF4A858CD3E926640C1E4920B5E3F5CFCC12F4389855E630BA","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
"20","Settings.xml","UpdateOrthoViewBlocks.dll","<deployed-root>\UpdateOrthoViewBlocks.dll","UpdateOrthoViewBlocks","True","5022D4D66D79E7E7D82F9FCB647DF8E1FE658A4694EB7794E363D5EA5517F5A9","acDoc.Editor.Command(""._netload"", fullPath)","True","Outer loader catch stops remaining sequence and shows MessageBox","Path is combined with OrthoLoader assembly directory."
1 Sequence ConfigFile ConfiguredPath ResolvedPath Assembly Exists Sha256 LoadMethod Required FailureBehavior Notes
2 1 Settings.xml AnnotateLineNumbers.dll <deployed-root>\AnnotateLineNumbers.dll AnnotateLineNumbers True 799BC277ED98BD870F01824180B5A945B24F016DFD9956A8CCC630AFE80FDFA4 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
3 2 Settings.xml AutoAnnotateView.dll <deployed-root>\AutoAnnotateView.dll AutoAnnotateView True EAE55411EC84AC747A3816EE65CD095648282BE44235351E7C9ED1C188BCB611 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
4 3 Settings.xml AutoLinenumberConnections.dll <deployed-root>\AutoLinenumberConnections.dll AutoLinenumberConnections True 0F6B2A759F2A63B9152B480B6968BDA20F42AD1D922F67CA6E6BFD31A0715F35 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
5 4 Settings.xml CheckOrthoView.dll <deployed-root>\CheckOrthoView.dll CheckOrthoView True 89DB5E537C2BAEC292CDD8A0A43819119850119D54958E8CC3C43E2136AB24A0 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
6 5 Settings.xml EnablerLoader.dll <deployed-root>\EnablerLoader.dll EnablerLoader True 745D625C27F92842F2EFF3C515DB48BB9FC0FE59B6E4559ACD696BCC93FF4C51 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
7 6 Settings.xml ExtentsIntersect.dll <deployed-root>\ExtentsIntersect.dll ExtentsIntersect True 59D2776E083D4BE2FBFBE4F43009EAA9CE0E81A1752815B45C510F80654169D9 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
8 7 Settings.xml GetComponentGeometry.dll <deployed-root>\GetComponentGeometry.dll GetComponentGeometry True 9EA8C48FEC4D36D32CC6AC88B78C434662C16D4484F86EFAA46ECC309E9F9142 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
9 8 Settings.xml GetLinenumberAnnotationText.dll <deployed-root>\GetLinenumberAnnotationText.dll GetLinenumberAnnotationText True 047E721DBE380061D9ABDD92BC5475440E3B7ADB2BD0F544D538BA24B121D30E acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
10 9 Settings.xml GetPlantScriptFolderPath.dll <deployed-root>\GetPlantScriptFolderPath.dll GetPlantScriptFolderPath True 5080A167A1DAF6C19BE08F6CAB678D490736B5E07E121A918A2915F0D9D8BF65 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
11 10 Settings.xml GetScriptParameters.dll <deployed-root>\GetScriptParameters.dll GetScriptParameters True 7FF7B0D26BE8D89FF4A5A4FA1C6EC17BDA1506BCCB78AFE0E650137CD7BA5E87 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
12 11 Settings.xml InsertElevation.dll <deployed-root>\InsertElevation.dll InsertElevation True B2D8B98F353D3DDF3A75A848E6922DC30478A1E5F98B372F24A049690492CA82 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
13 12 Settings.xml LoadedAssemblies.dll <deployed-root>\LoadedAssemblies.dll LoadedAssemblies True 277EB83C587A984DC2F558B8A7C86AA98E195A77AFA6FADD7DB83F2B801C0E4E acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
14 13 Settings.xml OrthoAutoAnnotate.dll <deployed-root>\OrthoAutoAnnotate.dll OrthoAutoAnnotate True 2E6BB2EBA0A98AA3550DFA4E661832FC7C3EE3DFF49BFC147BD4DFAD7A8596C6 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
15 14 Settings.xml P3DCopyMissingObjectsToOrthoDrawing.dll <deployed-root>\P3DCopyMissingObjectsToOrthoDrawing.dll P3DCopyMissingObjectsToOrthoDrawing True 6C879AFC7F35EC25E5E2FFF9FF0EE6EFEB155670DBFD5D0CDE9A0F629C5727B2 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
16 15 Settings.xml P3DNewMa.dll <deployed-root>\P3DNewMa.dll P3DNewMa True 97246EE9B24FD373551EF380C5AC0CA78CF7ED6A92581D5331B54445A2A948F8 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
17 16 Settings.xml P3DSetLayerForViewport.dll <deployed-root>\P3DSetLayerForViewport.dll P3DSetLayerForViewport True A28E58FDE4EBAA26450CA646C5A85F98C1A04AA42C0BFC5413D718243ACBF42B acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
18 17 Settings.xml PHPAnnotations.dll <deployed-root>\PHPAnnotations.dll PHPAnnotations True 816A693F1B775C5506043DD0461055F248D3897E96AC8285DAE29C5B71FFCA73 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
19 18 Settings.xml SwapAttributesMenuItem.dll <deployed-root>\SwapAttributesMenuItem.dll SwapAttributesMenuItem True 674C865E34F9C877561E03E2077F7F2C6852C3C8B6A0503ACAA7619F3E80A460 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
20 19 Settings.xml UpdateOrthoDrawings.dll <deployed-root>\UpdateOrthoDrawings.dll UpdateOrthoDrawings True 1492FFF1F56853DF4A858CD3E926640C1E4920B5E3F5CFCC12F4389855E630BA acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
21 20 Settings.xml UpdateOrthoViewBlocks.dll <deployed-root>\UpdateOrthoViewBlocks.dll UpdateOrthoViewBlocks True 5022D4D66D79E7E7D82F9FCB647DF8E1FE658A4694EB7794E363D5EA5517F5A9 acDoc.Editor.Command("._netload", fullPath) True Outer loader catch stops remaining sequence and shows MessageBox Path is combined with OrthoLoader assembly directory.
@@ -0,0 +1,53 @@
"RelativePath","Name","Extension","Length","LastWriteTimeUtc","Sha256","FileVersion","ProductVersion","AssemblyName","AssemblyVersion","TargetFramework","PeArchitecture"
"AnnotateLineNumbers.dll","AnnotateLineNumbers.dll",".dll","126976","2024-12-13T07:41:34.0000000Z","799BC277ED98BD870F01824180B5A945B24F016DFD9956A8CCC630AFE80FDFA4","1.0.4.1","v1.0.4","AnnotateLineNumbers","1.0.4.0",".NETFramework,Version=v4.7","x64"
"AutoAnnotateView.dll","AutoAnnotateView.dll",".dll","49664","2025-02-10T07:47:43.4844455Z","EAE55411EC84AC747A3816EE65CD095648282BE44235351E7C9ED1C188BCB611","1.0.4.6","v1.0.4","AutoAnnotateView","1.0.4.0",".NETFramework,Version=v4.7","x64"
"AutoElevation.dll","AutoElevation.dll",".dll","28160","2025-01-16T08:13:32.2554341Z","A8766B73B30F8F44213769EB7824F82F73ED418DE0EF49695E00A3EB7FC28885","1.0.4.5","v1.0.4","AutoElevation","1.0.4.0",".NETFramework,Version=v4.7","x64"
"AutoLinenumberConnections.dll","AutoLinenumberConnections.dll",".dll","41472","2024-12-13T07:41:34.0000000Z","0F6B2A759F2A63B9152B480B6968BDA20F42AD1D922F67CA6E6BFD31A0715F35","1.0.4.1","v1.0.4","AutoLinenumberConnections","1.0.4.0",".NETFramework,Version=v4.7","x64"
"b455ee6eaed79d76f084846a60ce3284","b455ee6eaed79d76f084846a60ce3284","","0","2023-12-29T11:13:44.6409171Z","E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",,,,,,
"CheckOrthoView.dll","CheckOrthoView.dll",".dll","14848","2024-12-13T07:41:34.0000000Z","89DB5E537C2BAEC292CDD8A0A43819119850119D54958E8CC3C43E2136AB24A0","1.0.4.1","v1.0.4","CheckOrthoView","1.0.4.0",".NETFramework,Version=v4.7","x64"
"EnablerLoader.dll","EnablerLoader.dll",".dll","6144","2024-12-13T07:41:34.0000000Z","745D625C27F92842F2EFF3C515DB48BB9FC0FE59B6E4559ACD696BCC93FF4C51","1.0.4.1","v1.0.4","EnablerLoader","1.0.4.0",".NETFramework,Version=v4.7","x64"
"ExtentsIntersect.dll","ExtentsIntersect.dll",".dll","6656","2024-12-13T07:41:34.0000000Z","59D2776E083D4BE2FBFBE4F43009EAA9CE0E81A1752815B45C510F80654169D9","1.0.4.1","v1.0.4","ExtentsIntersect","1.0.4.0",".NETFramework,Version=v4.7","x64"
"GetComponentGeometry.dll","GetComponentGeometry.dll",".dll","10240","2024-12-13T07:41:34.0000000Z","9EA8C48FEC4D36D32CC6AC88B78C434662C16D4484F86EFAA46ECC309E9F9142","1.0.4.1","v1.0.4","GetComponentGeometry","1.0.4.0",".NETFramework,Version=v4.7","x64"
"GetComponentGeometry.xml","GetComponentGeometry.xml",".xml","1239","2025-01-14T11:26:24.5054138Z","70169C3A3AAAFE5A2282E01D5B9B7C99F2F4FF9B7514553434302674ABE46C98",,,,,,
"GetLinenumberAnnotationText.dll","GetLinenumberAnnotationText.dll",".dll","23040","2024-12-13T07:41:34.0000000Z","047E721DBE380061D9ABDD92BC5475440E3B7ADB2BD0F544D538BA24B121D30E","1.0.4.1","v1.0.4","GetLinenumberAnnotationText","1.0.4.0",".NETFramework,Version=v4.7","x64"
"GetPlantScriptFolderPath.dll","GetPlantScriptFolderPath.dll",".dll","4608","2024-12-13T07:41:34.0000000Z","5080A167A1DAF6C19BE08F6CAB678D490736B5E07E121A918A2915F0D9D8BF65","1.0.4.1","v1.0.4","GetPlantScriptFolderPath","1.0.4.0",".NETFramework,Version=v4.7","x64"
"GetScriptParameters.dll","GetScriptParameters.dll",".dll","6656","2024-12-13T07:41:34.0000000Z","7FF7B0D26BE8D89FF4A5A4FA1C6EC17BDA1506BCCB78AFE0E650137CD7BA5E87","1.0.4.1","v1.0.4","GetScriptParameters","1.0.4.0",".NETFramework,Version=v4.7","x64"
"ico\button_BJ.png","button_BJ.png",".png","1235","2024-12-13T07:41:34.0000000Z","414F0A23E917D41A82C697B0E9CDDDF9BFCACD1627310BD5717AEA172418AA51",,,,,,
"ico\button_CAC.png","button_CAC.png",".png","1943","2024-12-13T07:41:34.0000000Z","FA2B8877F8B41C70BA62C737C40374394D6840A53DFE2D0B0F83463C4817C138",,,,,,
"ico\button_PXP-AAV.png","button_PXP-AAV.png",".png","1905","2024-12-13T07:41:34.0000000Z","6AB171963B553B434B5AA4BFBE91993B1782606AAF9B486FA23BB27BC1F0E4AA",,,,,,
"ico\button_PXP-AC.png","button_PXP-AC.png",".png","1751","2024-12-13T07:41:34.0000000Z","60A6BD62EF3E50BDDCD00D9C281F2399E6C9D42E0C2DAA1742273C0DC48FE9C3",,,,,,
"ico\button_PXP-AE.png","button_PXP-AE.png",".png","2001","2024-12-13T07:41:34.0000000Z","F1DCF0E908F5AF38CCD13ABA58B824E5B186430414499C0F623C1D5EEAD8DAD7",,,,,,
"ico\button_PXP-ALC.png","button_PXP-ALC.png",".png","1740","2024-12-13T07:41:34.0000000Z","19DB2449B66B95965155E6E3BC313BD52000FE38C95B0FAD90EF07DF53EA9CC9",,,,,,
"ico\button_PXP-COV.png","button_PXP-COV.png",".png","2007","2024-12-13T07:41:34.0000000Z","529BDD045961C244FBD0DE177B899AF9E7CE0F4506B3463C56D2704B3BF207B5",,,,,,
"ico\button_PXP-DAV.png","button_PXP-DAV.png",".png","1249","2025-01-28T06:29:03.3724433Z","A7932F2ABDAC652EA3A901A221AB3BE2BC80FCB76FB203D44FC63AF3681F51E3",,,,,,
"ico\button_PXP-DJ.png","button_PXP-DJ.png",".png","1470","2024-12-13T07:41:34.0000000Z","127957752DC2B6573CD2FD9A2791914BA22802E07E9B7E23CD3AE1FFF9E4FFC4",,,,,,
"ico\button_PXP-ELN.png","button_PXP-ELN.png",".png","1927","2024-12-13T07:41:34.0000000Z","DF32E6A465D5C196A17F3F96473315590DF2D71995F63D2D241D7599B62C99BB",,,,,,
"ico\button_PXP-ESN.png","button_PXP-ESN.png",".png","1636","2024-12-13T07:41:34.0000000Z","0F089184CFD428DA3620F9C0AD2DCBFC21B31ED34FA301E8D5D45923783C0CC7",,,,,,
"ico\button_PXP-IE.png","button_PXP-IE.png",".png","1885","2024-12-13T07:41:34.0000000Z","F1C6373BFAF82E1908AF371D5F21133D27E0B84AFC706A703530855A2046FE43",,,,,,
"ico\button_PXP-IOD.png","button_PXP-IOD.png",".png","1942","2024-12-13T07:41:34.0000000Z","494E90C899A0BB5BB365B0E1452E92A68359610C5A38A37D09F520A39BDB3899",,,,,,
"ico\button_PXP-LN.png","button_PXP-LN.png",".png","2024","2024-12-13T07:41:34.0000000Z","F3305ED6D266E29FA475D4C8A7DF38D2D2A1776A4CE379B876B6CFA278B2FE5D",,,,,,
"ico\button_PXP-MA.png","button_PXP-MA.png",".png","1907","2024-12-13T07:41:34.0000000Z","9386249121644DCF4B9C70491F561E8B6E5BAAE87EBB2C76A84E46B10A60C8C3",,,,,,
"ico\button_PXP-OA.png","button_PXP-OA.png",".png","1999","2024-12-13T07:41:34.0000000Z","EAA2AD7EE5C6B7F3716AF1D7690C76AE59229AE9B6BA02009F5009CD9307F4E8",,,,,,
"ico\button_PXP-OSI.png","button_PXP-OSI.png",".png","1508","2024-12-13T07:41:34.0000000Z","422D10B6EBDD76085CF9C5985391CCA060464B200D6792D604658AAE47F12CEE",,,,,,
"ico\button_PXP-RA.png","button_PXP-RA.png",".png","1826","2024-12-13T07:41:34.0000000Z","1DB3F39C6CCA4EABE79D81DE6DCF9900649CDC9064F2EBF5E45F9AD849B8317F",,,,,,
"ico\button_PXP-RMP.png","button_PXP-RMP.png",".png","1759","2024-12-13T07:41:34.0000000Z","156026EC6DEB7BDBE720047409E9A25615D650D8634C2F0BAF49A71E27135258",,,,,,
"ico\button_PXP-ULN.png","button_PXP-ULN.png",".png","1928","2024-12-13T07:41:34.0000000Z","B37EBB460691EAA7BC3A91DF05C27FE7CC1F0E9F9D69BDA7703956EAA7AA785C",,,,,,
"ico\button_PXP-UOB.png","button_PXP-UOB.png",".png","1569","2024-12-13T07:41:34.0000000Z","3BC16B9923CCD34CF10F403CD65732B217E255E89539174841E7F30D9DFD2DCD",,,,,,
"InsertElevation.dll","InsertElevation.dll",".dll","24576","2025-01-16T08:13:32.2504470Z","B2D8B98F353D3DDF3A75A848E6922DC30478A1E5F98B372F24A049690492CA82","1.0.4.5","v1.0.4","InsertElevation","1.0.4.0",".NETFramework,Version=v4.7","x64"
"LoadedAssemblies.dll","LoadedAssemblies.dll",".dll","4608","2024-12-13T07:41:34.0000000Z","277EB83C587A984DC2F558B8A7C86AA98E195A77AFA6FADD7DB83F2B801C0E4E","1.0.4.1","v1.0.4","LoadedAssemblies","1.0.4.0",".NETFramework,Version=v4.7","x64"
"OrthoAutoAnnotate.dll","OrthoAutoAnnotate.dll",".dll","108544","2025-02-10T07:45:33.3280516Z","2E6BB2EBA0A98AA3550DFA4E661832FC7C3EE3DFF49BFC147BD4DFAD7A8596C6","1.0.4.6","v1.0.4","OrthoAutoAnnotate","1.0.4.0",".NETFramework,Version=v4.7","x64"
"OrthoLoader.dll","OrthoLoader.dll",".dll","18944","2025-02-24T06:59:01.9094468Z","D418F2CBDD134C0156E2D332BD7F9ED471B9A1E0581FE42EDF98BBE01CB3345D","1.0.4.7","v1.0.4","OrthoLoader","1.0.4.0",".NETFramework,Version=v4.7","x64"
"P3DCopyMissingObjectsToOrthoDrawing.dll","P3DCopyMissingObjectsToOrthoDrawing.dll",".dll","14336","2024-12-13T07:41:34.0000000Z","6C879AFC7F35EC25E5E2FFF9FF0EE6EFEB155670DBFD5D0CDE9A0F629C5727B2","1.0.4.1","v1.0.4","P3DCopyMissingObjectsToOrthoDrawing","1.0.4.0",".NETFramework,Version=v4.7","x64"
"P3DNewMa.dll","P3DNewMa.dll",".dll","103936","2025-02-24T06:59:03.1350320Z","97246EE9B24FD373551EF380C5AC0CA78CF7ED6A92581D5331B54445A2A948F8","1.0.4.7","v1.0.4","P3DNewMa","1.0.4.0",".NETFramework,Version=v4.7","x64"
"P3DSetLayerForViewport.dll","P3DSetLayerForViewport.dll",".dll","4608","2024-12-13T07:41:34.0000000Z","A28E58FDE4EBAA26450CA646C5A85F98C1A04AA42C0BFC5413D718243ACBF42B","1.0.4.1","v1.0.4","P3DSetLayerForViewport","1.0.4.0",".NETFramework,Version=v4.7","x64"
"PHPAnnotations.dll","PHPAnnotations.dll",".dll","69120","2024-12-13T07:41:34.0000000Z","816A693F1B775C5506043DD0461055F248D3897E96AC8285DAE29C5B71FFCA73","1.0.4.1","v1.0.4","PHPAnnotations","1.0.4.0",".NETFramework,Version=v4.7","x64"
"Settings.xml","Settings.xml",".xml","136576","2025-01-31T07:28:24.1891507Z","AFEDC7526923ACE1DC60374F98F171809B36992262A37E1F11828F2B8D9799CB",,,,,,
"SwapAttributesMenuItem.dll","SwapAttributesMenuItem.dll",".dll","11264","2024-12-13T07:41:34.0000000Z","674C865E34F9C877561E03E2077F7F2C6852C3C8B6A0503ACAA7619F3E80A460","1.0.4.1","v1.0.4","SwapAttributesMenuItem","1.0.4.0",".NETFramework,Version=v4.7","x64"
"Template.dwg","Template.dwg",".dwg","148438","2025-01-30T13:16:13.0000000Z","EA279A30F113660CF53585451083BAEB0A01CA58C8F9A767C4B7C2A5E66ECCA3",,,,,,
"test.txt","test.txt",".txt","0","2025-01-16T09:56:52.0597137Z","E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",,,,,,
"UpdateOrthoDrawings.dll","UpdateOrthoDrawings.dll",".dll","45568","2025-02-24T06:59:02.4829428Z","1492FFF1F56853DF4A858CD3E926640C1E4920B5E3F5CFCC12F4389855E630BA","1.0.4.2","v1.0.4","UpdateOrthoDrawings","1.0.4.0",".NETFramework,Version=v4.7","x64"
"UpdateOrthoViewBlocks.dll","UpdateOrthoViewBlocks.dll",".dll","15360","2024-12-13T07:41:34.0000000Z","5022D4D66D79E7E7D82F9FCB647DF8E1FE658A4694EB7794E363D5EA5517F5A9","1.0.4.1","v1.0.4","UpdateOrthoViewBlocks","1.0.4.0",".NETFramework,Version=v4.7","x64"
"Справка по работе с палитрой.docx","Справка по работе с палитрой.docx",".docx","855301","2025-02-05T09:53:08.1186958Z","B6DC65BA17C4EA79DBCCC501909BEDBF56EB6A9F1E24BFAD1B01158B6EC639D0",,,,,,
"Справка по работе с палитрой.pdf","Справка по работе с палитрой.pdf",".pdf","744035","2025-02-05T09:53:21.3752687Z","332CA70D3264C28BC712CA790157D0CD03BE7E07F42603DAF9247600271B7B75",,,,,,
"Справка.docx","Справка.docx",".docx","87889","2025-02-06T05:13:36.4991443Z","14BA9BD252FB6DF37C4D151787E8799AB1703847C1DEC24F3EFE4D6805B0EB12",,,,,,
"Справка.pdf","Справка.pdf",".pdf","154074","2025-02-06T05:14:24.2809131Z","EB840514755A9F56ABC8351B8EC41233FE2512118DB2D4BA0ACD46E74D2C7DC9",,,,,,
1 RelativePath Name Extension Length LastWriteTimeUtc Sha256 FileVersion ProductVersion AssemblyName AssemblyVersion TargetFramework PeArchitecture
2 AnnotateLineNumbers.dll AnnotateLineNumbers.dll .dll 126976 2024-12-13T07:41:34.0000000Z 799BC277ED98BD870F01824180B5A945B24F016DFD9956A8CCC630AFE80FDFA4 1.0.4.1 v1.0.4 AnnotateLineNumbers 1.0.4.0 .NETFramework,Version=v4.7 x64
3 AutoAnnotateView.dll AutoAnnotateView.dll .dll 49664 2025-02-10T07:47:43.4844455Z EAE55411EC84AC747A3816EE65CD095648282BE44235351E7C9ED1C188BCB611 1.0.4.6 v1.0.4 AutoAnnotateView 1.0.4.0 .NETFramework,Version=v4.7 x64
4 AutoElevation.dll AutoElevation.dll .dll 28160 2025-01-16T08:13:32.2554341Z A8766B73B30F8F44213769EB7824F82F73ED418DE0EF49695E00A3EB7FC28885 1.0.4.5 v1.0.4 AutoElevation 1.0.4.0 .NETFramework,Version=v4.7 x64
5 AutoLinenumberConnections.dll AutoLinenumberConnections.dll .dll 41472 2024-12-13T07:41:34.0000000Z 0F6B2A759F2A63B9152B480B6968BDA20F42AD1D922F67CA6E6BFD31A0715F35 1.0.4.1 v1.0.4 AutoLinenumberConnections 1.0.4.0 .NETFramework,Version=v4.7 x64
6 b455ee6eaed79d76f084846a60ce3284 b455ee6eaed79d76f084846a60ce3284 0 2023-12-29T11:13:44.6409171Z E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
7 CheckOrthoView.dll CheckOrthoView.dll .dll 14848 2024-12-13T07:41:34.0000000Z 89DB5E537C2BAEC292CDD8A0A43819119850119D54958E8CC3C43E2136AB24A0 1.0.4.1 v1.0.4 CheckOrthoView 1.0.4.0 .NETFramework,Version=v4.7 x64
8 EnablerLoader.dll EnablerLoader.dll .dll 6144 2024-12-13T07:41:34.0000000Z 745D625C27F92842F2EFF3C515DB48BB9FC0FE59B6E4559ACD696BCC93FF4C51 1.0.4.1 v1.0.4 EnablerLoader 1.0.4.0 .NETFramework,Version=v4.7 x64
9 ExtentsIntersect.dll ExtentsIntersect.dll .dll 6656 2024-12-13T07:41:34.0000000Z 59D2776E083D4BE2FBFBE4F43009EAA9CE0E81A1752815B45C510F80654169D9 1.0.4.1 v1.0.4 ExtentsIntersect 1.0.4.0 .NETFramework,Version=v4.7 x64
10 GetComponentGeometry.dll GetComponentGeometry.dll .dll 10240 2024-12-13T07:41:34.0000000Z 9EA8C48FEC4D36D32CC6AC88B78C434662C16D4484F86EFAA46ECC309E9F9142 1.0.4.1 v1.0.4 GetComponentGeometry 1.0.4.0 .NETFramework,Version=v4.7 x64
11 GetComponentGeometry.xml GetComponentGeometry.xml .xml 1239 2025-01-14T11:26:24.5054138Z 70169C3A3AAAFE5A2282E01D5B9B7C99F2F4FF9B7514553434302674ABE46C98
12 GetLinenumberAnnotationText.dll GetLinenumberAnnotationText.dll .dll 23040 2024-12-13T07:41:34.0000000Z 047E721DBE380061D9ABDD92BC5475440E3B7ADB2BD0F544D538BA24B121D30E 1.0.4.1 v1.0.4 GetLinenumberAnnotationText 1.0.4.0 .NETFramework,Version=v4.7 x64
13 GetPlantScriptFolderPath.dll GetPlantScriptFolderPath.dll .dll 4608 2024-12-13T07:41:34.0000000Z 5080A167A1DAF6C19BE08F6CAB678D490736B5E07E121A918A2915F0D9D8BF65 1.0.4.1 v1.0.4 GetPlantScriptFolderPath 1.0.4.0 .NETFramework,Version=v4.7 x64
14 GetScriptParameters.dll GetScriptParameters.dll .dll 6656 2024-12-13T07:41:34.0000000Z 7FF7B0D26BE8D89FF4A5A4FA1C6EC17BDA1506BCCB78AFE0E650137CD7BA5E87 1.0.4.1 v1.0.4 GetScriptParameters 1.0.4.0 .NETFramework,Version=v4.7 x64
15 ico\button_BJ.png button_BJ.png .png 1235 2024-12-13T07:41:34.0000000Z 414F0A23E917D41A82C697B0E9CDDDF9BFCACD1627310BD5717AEA172418AA51
16 ico\button_CAC.png button_CAC.png .png 1943 2024-12-13T07:41:34.0000000Z FA2B8877F8B41C70BA62C737C40374394D6840A53DFE2D0B0F83463C4817C138
17 ico\button_PXP-AAV.png button_PXP-AAV.png .png 1905 2024-12-13T07:41:34.0000000Z 6AB171963B553B434B5AA4BFBE91993B1782606AAF9B486FA23BB27BC1F0E4AA
18 ico\button_PXP-AC.png button_PXP-AC.png .png 1751 2024-12-13T07:41:34.0000000Z 60A6BD62EF3E50BDDCD00D9C281F2399E6C9D42E0C2DAA1742273C0DC48FE9C3
19 ico\button_PXP-AE.png button_PXP-AE.png .png 2001 2024-12-13T07:41:34.0000000Z F1DCF0E908F5AF38CCD13ABA58B824E5B186430414499C0F623C1D5EEAD8DAD7
20 ico\button_PXP-ALC.png button_PXP-ALC.png .png 1740 2024-12-13T07:41:34.0000000Z 19DB2449B66B95965155E6E3BC313BD52000FE38C95B0FAD90EF07DF53EA9CC9
21 ico\button_PXP-COV.png button_PXP-COV.png .png 2007 2024-12-13T07:41:34.0000000Z 529BDD045961C244FBD0DE177B899AF9E7CE0F4506B3463C56D2704B3BF207B5
22 ico\button_PXP-DAV.png button_PXP-DAV.png .png 1249 2025-01-28T06:29:03.3724433Z A7932F2ABDAC652EA3A901A221AB3BE2BC80FCB76FB203D44FC63AF3681F51E3
23 ico\button_PXP-DJ.png button_PXP-DJ.png .png 1470 2024-12-13T07:41:34.0000000Z 127957752DC2B6573CD2FD9A2791914BA22802E07E9B7E23CD3AE1FFF9E4FFC4
24 ico\button_PXP-ELN.png button_PXP-ELN.png .png 1927 2024-12-13T07:41:34.0000000Z DF32E6A465D5C196A17F3F96473315590DF2D71995F63D2D241D7599B62C99BB
25 ico\button_PXP-ESN.png button_PXP-ESN.png .png 1636 2024-12-13T07:41:34.0000000Z 0F089184CFD428DA3620F9C0AD2DCBFC21B31ED34FA301E8D5D45923783C0CC7
26 ico\button_PXP-IE.png button_PXP-IE.png .png 1885 2024-12-13T07:41:34.0000000Z F1C6373BFAF82E1908AF371D5F21133D27E0B84AFC706A703530855A2046FE43
27 ico\button_PXP-IOD.png button_PXP-IOD.png .png 1942 2024-12-13T07:41:34.0000000Z 494E90C899A0BB5BB365B0E1452E92A68359610C5A38A37D09F520A39BDB3899
28 ico\button_PXP-LN.png button_PXP-LN.png .png 2024 2024-12-13T07:41:34.0000000Z F3305ED6D266E29FA475D4C8A7DF38D2D2A1776A4CE379B876B6CFA278B2FE5D
29 ico\button_PXP-MA.png button_PXP-MA.png .png 1907 2024-12-13T07:41:34.0000000Z 9386249121644DCF4B9C70491F561E8B6E5BAAE87EBB2C76A84E46B10A60C8C3
30 ico\button_PXP-OA.png button_PXP-OA.png .png 1999 2024-12-13T07:41:34.0000000Z EAA2AD7EE5C6B7F3716AF1D7690C76AE59229AE9B6BA02009F5009CD9307F4E8
31 ico\button_PXP-OSI.png button_PXP-OSI.png .png 1508 2024-12-13T07:41:34.0000000Z 422D10B6EBDD76085CF9C5985391CCA060464B200D6792D604658AAE47F12CEE
32 ico\button_PXP-RA.png button_PXP-RA.png .png 1826 2024-12-13T07:41:34.0000000Z 1DB3F39C6CCA4EABE79D81DE6DCF9900649CDC9064F2EBF5E45F9AD849B8317F
33 ico\button_PXP-RMP.png button_PXP-RMP.png .png 1759 2024-12-13T07:41:34.0000000Z 156026EC6DEB7BDBE720047409E9A25615D650D8634C2F0BAF49A71E27135258
34 ico\button_PXP-ULN.png button_PXP-ULN.png .png 1928 2024-12-13T07:41:34.0000000Z B37EBB460691EAA7BC3A91DF05C27FE7CC1F0E9F9D69BDA7703956EAA7AA785C
35 ico\button_PXP-UOB.png button_PXP-UOB.png .png 1569 2024-12-13T07:41:34.0000000Z 3BC16B9923CCD34CF10F403CD65732B217E255E89539174841E7F30D9DFD2DCD
36 InsertElevation.dll InsertElevation.dll .dll 24576 2025-01-16T08:13:32.2504470Z B2D8B98F353D3DDF3A75A848E6922DC30478A1E5F98B372F24A049690492CA82 1.0.4.5 v1.0.4 InsertElevation 1.0.4.0 .NETFramework,Version=v4.7 x64
37 LoadedAssemblies.dll LoadedAssemblies.dll .dll 4608 2024-12-13T07:41:34.0000000Z 277EB83C587A984DC2F558B8A7C86AA98E195A77AFA6FADD7DB83F2B801C0E4E 1.0.4.1 v1.0.4 LoadedAssemblies 1.0.4.0 .NETFramework,Version=v4.7 x64
38 OrthoAutoAnnotate.dll OrthoAutoAnnotate.dll .dll 108544 2025-02-10T07:45:33.3280516Z 2E6BB2EBA0A98AA3550DFA4E661832FC7C3EE3DFF49BFC147BD4DFAD7A8596C6 1.0.4.6 v1.0.4 OrthoAutoAnnotate 1.0.4.0 .NETFramework,Version=v4.7 x64
39 OrthoLoader.dll OrthoLoader.dll .dll 18944 2025-02-24T06:59:01.9094468Z D418F2CBDD134C0156E2D332BD7F9ED471B9A1E0581FE42EDF98BBE01CB3345D 1.0.4.7 v1.0.4 OrthoLoader 1.0.4.0 .NETFramework,Version=v4.7 x64
40 P3DCopyMissingObjectsToOrthoDrawing.dll P3DCopyMissingObjectsToOrthoDrawing.dll .dll 14336 2024-12-13T07:41:34.0000000Z 6C879AFC7F35EC25E5E2FFF9FF0EE6EFEB155670DBFD5D0CDE9A0F629C5727B2 1.0.4.1 v1.0.4 P3DCopyMissingObjectsToOrthoDrawing 1.0.4.0 .NETFramework,Version=v4.7 x64
41 P3DNewMa.dll P3DNewMa.dll .dll 103936 2025-02-24T06:59:03.1350320Z 97246EE9B24FD373551EF380C5AC0CA78CF7ED6A92581D5331B54445A2A948F8 1.0.4.7 v1.0.4 P3DNewMa 1.0.4.0 .NETFramework,Version=v4.7 x64
42 P3DSetLayerForViewport.dll P3DSetLayerForViewport.dll .dll 4608 2024-12-13T07:41:34.0000000Z A28E58FDE4EBAA26450CA646C5A85F98C1A04AA42C0BFC5413D718243ACBF42B 1.0.4.1 v1.0.4 P3DSetLayerForViewport 1.0.4.0 .NETFramework,Version=v4.7 x64
43 PHPAnnotations.dll PHPAnnotations.dll .dll 69120 2024-12-13T07:41:34.0000000Z 816A693F1B775C5506043DD0461055F248D3897E96AC8285DAE29C5B71FFCA73 1.0.4.1 v1.0.4 PHPAnnotations 1.0.4.0 .NETFramework,Version=v4.7 x64
44 Settings.xml Settings.xml .xml 136576 2025-01-31T07:28:24.1891507Z AFEDC7526923ACE1DC60374F98F171809B36992262A37E1F11828F2B8D9799CB
45 SwapAttributesMenuItem.dll SwapAttributesMenuItem.dll .dll 11264 2024-12-13T07:41:34.0000000Z 674C865E34F9C877561E03E2077F7F2C6852C3C8B6A0503ACAA7619F3E80A460 1.0.4.1 v1.0.4 SwapAttributesMenuItem 1.0.4.0 .NETFramework,Version=v4.7 x64
46 Template.dwg Template.dwg .dwg 148438 2025-01-30T13:16:13.0000000Z EA279A30F113660CF53585451083BAEB0A01CA58C8F9A767C4B7C2A5E66ECCA3
47 test.txt test.txt .txt 0 2025-01-16T09:56:52.0597137Z E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
48 UpdateOrthoDrawings.dll UpdateOrthoDrawings.dll .dll 45568 2025-02-24T06:59:02.4829428Z 1492FFF1F56853DF4A858CD3E926640C1E4920B5E3F5CFCC12F4389855E630BA 1.0.4.2 v1.0.4 UpdateOrthoDrawings 1.0.4.0 .NETFramework,Version=v4.7 x64
49 UpdateOrthoViewBlocks.dll UpdateOrthoViewBlocks.dll .dll 15360 2024-12-13T07:41:34.0000000Z 5022D4D66D79E7E7D82F9FCB647DF8E1FE658A4694EB7794E363D5EA5517F5A9 1.0.4.1 v1.0.4 UpdateOrthoViewBlocks 1.0.4.0 .NETFramework,Version=v4.7 x64
50 Справка по работе с палитрой.docx Справка по работе с палитрой.docx .docx 855301 2025-02-05T09:53:08.1186958Z B6DC65BA17C4EA79DBCCC501909BEDBF56EB6A9F1E24BFAD1B01158B6EC639D0
51 Справка по работе с палитрой.pdf Справка по работе с палитрой.pdf .pdf 744035 2025-02-05T09:53:21.3752687Z 332CA70D3264C28BC712CA790157D0CD03BE7E07F42603DAF9247600271B7B75
52 Справка.docx Справка.docx .docx 87889 2025-02-06T05:13:36.4991443Z 14BA9BD252FB6DF37C4D151787E8799AB1703847C1DEC24F3EFE4D6805B0EB12
53 Справка.pdf Справка.pdf .pdf 154074 2025-02-06T05:14:24.2809131Z EB840514755A9F56ABC8351B8EC41233FE2512118DB2D4BA0ACD46E74D2C7DC9
@@ -0,0 +1,23 @@
"DeployedDll","DeployedSha256","FileVersion","AssemblyVersion","LegacyProject","LegacyCsproj","LegacyOutputName","TargetFramework","PlatformTarget","CommandCount","RibbonRole","ConfigurationSource","MatchStatus"
"AnnotateLineNumbers.dll","799BC277ED98BD870F01824180B5A945B24F016DFD9956A8CCC630AFE80FDFA4","1.0.4.1","1.0.4.0","AnnotateLineNumbers","AnnotateLineNumbers\AnnotateLineNumbers.csproj","AnnotateLineNumbers","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"AutoAnnotateView.dll","EAE55411EC84AC747A3816EE65CD095648282BE44235351E7C9ED1C188BCB611","1.0.4.6","1.0.4.0","AutoAnnotateView","AutoAnnotateView\AutoAnnotateView.csproj","AutoAnnotateView","v4.7","x64",,,"Settings.xml","LIKELY_SOURCE_MATCH"
"AutoElevation.dll","A8766B73B30F8F44213769EB7824F82F73ED418DE0EF49695E00A3EB7FC28885","1.0.4.5","1.0.4.0","AutoElevation","AutoElevation\AutoElevation.csproj","AutoElevation","v4.7","x64",,,,"LIKELY_SOURCE_MATCH"
"AutoLinenumberConnections.dll","0F6B2A759F2A63B9152B480B6968BDA20F42AD1D922F67CA6E6BFD31A0715F35","1.0.4.1","1.0.4.0","AutoLinenumberConnections","AutoLinenumberConnections\AutoLinenumberConnections.csproj","AutoLinenumberConnections","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"CheckOrthoView.dll","89DB5E537C2BAEC292CDD8A0A43819119850119D54958E8CC3C43E2136AB24A0","1.0.4.1","1.0.4.0","CheckOrthoView","CheckOrthoView\CheckOrthoView.csproj","CheckOrthoView","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"EnablerLoader.dll","745D625C27F92842F2EFF3C515DB48BB9FC0FE59B6E4559ACD696BCC93FF4C51","1.0.4.1","1.0.4.0","EnablerLoader","EnablerLoader\EnablerLoader.csproj","EnablerLoader","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"ExtentsIntersect.dll","59D2776E083D4BE2FBFBE4F43009EAA9CE0E81A1752815B45C510F80654169D9","1.0.4.1","1.0.4.0","ExtentsIntersect","ExtentsIntersect\ExtentsIntersect.csproj","ExtentsIntersect","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"GetComponentGeometry.dll","9EA8C48FEC4D36D32CC6AC88B78C434662C16D4484F86EFAA46ECC309E9F9142","1.0.4.1","1.0.4.0","GetComponentGeometry","GetComponentGeometry\GetComponentGeometry.csproj","GetComponentGeometry","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"GetLinenumberAnnotationText.dll","047E721DBE380061D9ABDD92BC5475440E3B7ADB2BD0F544D538BA24B121D30E","1.0.4.1","1.0.4.0","GetLinenumberAnnotationText","GetLinenumberAnnotationText\GetLinenumberAnnotationText.csproj","GetLinenumberAnnotationText","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"GetPlantScriptFolderPath.dll","5080A167A1DAF6C19BE08F6CAB678D490736B5E07E121A918A2915F0D9D8BF65","1.0.4.1","1.0.4.0","GetPlantScriptFolderPath","GetPlantScriptFolderPath\GetPlantScriptFolderPath.csproj","GetPlantScriptFolderPath","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"GetScriptParameters.dll","7FF7B0D26BE8D89FF4A5A4FA1C6EC17BDA1506BCCB78AFE0E650137CD7BA5E87","1.0.4.1","1.0.4.0","GetScriptParameters","GetScriptParameters\GetScriptParameters.csproj","GetScriptParameters","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"InsertElevation.dll","B2D8B98F353D3DDF3A75A848E6922DC30478A1E5F98B372F24A049690492CA82","1.0.4.5","1.0.4.0","InsertElevation","InsertElevation\InsertElevation.csproj","InsertElevation","v4.7","x64",,,"Settings.xml","MULTIPLE_CANDIDATES"
"LoadedAssemblies.dll","277EB83C587A984DC2F558B8A7C86AA98E195A77AFA6FADD7DB83F2B801C0E4E","1.0.4.1","1.0.4.0","LoadedAssemblies","LoadedAssemblies\LoadedAssemblies.csproj","LoadedAssemblies","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"OrthoAutoAnnotate.dll","2E6BB2EBA0A98AA3550DFA4E661832FC7C3EE3DFF49BFC147BD4DFAD7A8596C6","1.0.4.6","1.0.4.0","OrthoAutoAnnotate","OrthoAutoAnnotate\OrthoAutoAnnotate.csproj","OrthoAutoAnnotate","v4.7","x64",,,"Settings.xml","LIKELY_SOURCE_MATCH"
"OrthoLoader.dll","D418F2CBDD134C0156E2D332BD7F9ED471B9A1E0581FE42EDF98BBE01CB3345D","1.0.4.7","1.0.4.0","OrthoLoader","OrthoLoader\OrthoLoader.csproj","OrthoLoader","v4.7","x64",,"Central ribbon/loader",,"LIKELY_SOURCE_MATCH"
"P3DCopyMissingObjectsToOrthoDrawing.dll","6C879AFC7F35EC25E5E2FFF9FF0EE6EFEB155670DBFD5D0CDE9A0F629C5727B2","1.0.4.1","1.0.4.0","P3DCopyMissingObjectsToOrthoDrawing","P3DCopyMissingObjectsToOrthoDrawing\P3DCopyMissingObjectsToOrthoDrawing.csproj","P3DCopyMissingObjectsToOrthoDrawing","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"P3DNewMa.dll","97246EE9B24FD373551EF380C5AC0CA78CF7ED6A92581D5331B54445A2A948F8","1.0.4.7","1.0.4.0","P3DNewMa","P3DNewMa\P3DNewMa.csproj","P3DNewMa","v4.7","x64",,,"Settings.xml","LIKELY_SOURCE_MATCH"
"P3DSetLayerForViewport.dll","A28E58FDE4EBAA26450CA646C5A85F98C1A04AA42C0BFC5413D718243ACBF42B","1.0.4.1","1.0.4.0","P3DSetLayerForViewport","P3DSetLayerForViewport\P3DSetLayerForViewport.csproj","P3DSetLayerForViewport","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"PHPAnnotations.dll","816A693F1B775C5506043DD0461055F248D3897E96AC8285DAE29C5B71FFCA73","1.0.4.1","1.0.4.0","PHPAnnotations","PHPAnnotations\PHPAnnotations.csproj","PHPAnnotations","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"SwapAttributesMenuItem.dll","674C865E34F9C877561E03E2077F7F2C6852C3C8B6A0503ACAA7619F3E80A460","1.0.4.1","1.0.4.0","SwapAttributesMenuItem","SwapAttributesMenuItem\SwapAttributesMenuItem.csproj","SwapAttributesMenuItem","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
"UpdateOrthoDrawings.dll","1492FFF1F56853DF4A858CD3E926640C1E4920B5E3F5CFCC12F4389855E630BA","1.0.4.2","1.0.4.0","UpdateOrthoDrawings","UpdateOrthoDrawings\UpdateOrthoDrawings.csproj","UpdateOrthoDrawings","v4.7","x64",,,"Settings.xml","LIKELY_SOURCE_MATCH"
"UpdateOrthoViewBlocks.dll","5022D4D66D79E7E7D82F9FCB647DF8E1FE658A4694EB7794E363D5EA5517F5A9","1.0.4.1","1.0.4.0","UpdateOrthoViewBlocks","UpdateOrthoViewBlocks\UpdateOrthoViewBlocks.csproj","UpdateOrthoViewBlocks","v4.7","x64",,,"Settings.xml","EXACT_SOURCE_MATCH"
1 DeployedDll DeployedSha256 FileVersion AssemblyVersion LegacyProject LegacyCsproj LegacyOutputName TargetFramework PlatformTarget CommandCount RibbonRole ConfigurationSource MatchStatus
2 AnnotateLineNumbers.dll 799BC277ED98BD870F01824180B5A945B24F016DFD9956A8CCC630AFE80FDFA4 1.0.4.1 1.0.4.0 AnnotateLineNumbers AnnotateLineNumbers\AnnotateLineNumbers.csproj AnnotateLineNumbers v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
3 AutoAnnotateView.dll EAE55411EC84AC747A3816EE65CD095648282BE44235351E7C9ED1C188BCB611 1.0.4.6 1.0.4.0 AutoAnnotateView AutoAnnotateView\AutoAnnotateView.csproj AutoAnnotateView v4.7 x64 Settings.xml LIKELY_SOURCE_MATCH
4 AutoElevation.dll A8766B73B30F8F44213769EB7824F82F73ED418DE0EF49695E00A3EB7FC28885 1.0.4.5 1.0.4.0 AutoElevation AutoElevation\AutoElevation.csproj AutoElevation v4.7 x64 LIKELY_SOURCE_MATCH
5 AutoLinenumberConnections.dll 0F6B2A759F2A63B9152B480B6968BDA20F42AD1D922F67CA6E6BFD31A0715F35 1.0.4.1 1.0.4.0 AutoLinenumberConnections AutoLinenumberConnections\AutoLinenumberConnections.csproj AutoLinenumberConnections v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
6 CheckOrthoView.dll 89DB5E537C2BAEC292CDD8A0A43819119850119D54958E8CC3C43E2136AB24A0 1.0.4.1 1.0.4.0 CheckOrthoView CheckOrthoView\CheckOrthoView.csproj CheckOrthoView v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
7 EnablerLoader.dll 745D625C27F92842F2EFF3C515DB48BB9FC0FE59B6E4559ACD696BCC93FF4C51 1.0.4.1 1.0.4.0 EnablerLoader EnablerLoader\EnablerLoader.csproj EnablerLoader v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
8 ExtentsIntersect.dll 59D2776E083D4BE2FBFBE4F43009EAA9CE0E81A1752815B45C510F80654169D9 1.0.4.1 1.0.4.0 ExtentsIntersect ExtentsIntersect\ExtentsIntersect.csproj ExtentsIntersect v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
9 GetComponentGeometry.dll 9EA8C48FEC4D36D32CC6AC88B78C434662C16D4484F86EFAA46ECC309E9F9142 1.0.4.1 1.0.4.0 GetComponentGeometry GetComponentGeometry\GetComponentGeometry.csproj GetComponentGeometry v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
10 GetLinenumberAnnotationText.dll 047E721DBE380061D9ABDD92BC5475440E3B7ADB2BD0F544D538BA24B121D30E 1.0.4.1 1.0.4.0 GetLinenumberAnnotationText GetLinenumberAnnotationText\GetLinenumberAnnotationText.csproj GetLinenumberAnnotationText v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
11 GetPlantScriptFolderPath.dll 5080A167A1DAF6C19BE08F6CAB678D490736B5E07E121A918A2915F0D9D8BF65 1.0.4.1 1.0.4.0 GetPlantScriptFolderPath GetPlantScriptFolderPath\GetPlantScriptFolderPath.csproj GetPlantScriptFolderPath v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
12 GetScriptParameters.dll 7FF7B0D26BE8D89FF4A5A4FA1C6EC17BDA1506BCCB78AFE0E650137CD7BA5E87 1.0.4.1 1.0.4.0 GetScriptParameters GetScriptParameters\GetScriptParameters.csproj GetScriptParameters v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
13 InsertElevation.dll B2D8B98F353D3DDF3A75A848E6922DC30478A1E5F98B372F24A049690492CA82 1.0.4.5 1.0.4.0 InsertElevation InsertElevation\InsertElevation.csproj InsertElevation v4.7 x64 Settings.xml MULTIPLE_CANDIDATES
14 LoadedAssemblies.dll 277EB83C587A984DC2F558B8A7C86AA98E195A77AFA6FADD7DB83F2B801C0E4E 1.0.4.1 1.0.4.0 LoadedAssemblies LoadedAssemblies\LoadedAssemblies.csproj LoadedAssemblies v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
15 OrthoAutoAnnotate.dll 2E6BB2EBA0A98AA3550DFA4E661832FC7C3EE3DFF49BFC147BD4DFAD7A8596C6 1.0.4.6 1.0.4.0 OrthoAutoAnnotate OrthoAutoAnnotate\OrthoAutoAnnotate.csproj OrthoAutoAnnotate v4.7 x64 Settings.xml LIKELY_SOURCE_MATCH
16 OrthoLoader.dll D418F2CBDD134C0156E2D332BD7F9ED471B9A1E0581FE42EDF98BBE01CB3345D 1.0.4.7 1.0.4.0 OrthoLoader OrthoLoader\OrthoLoader.csproj OrthoLoader v4.7 x64 Central ribbon/loader LIKELY_SOURCE_MATCH
17 P3DCopyMissingObjectsToOrthoDrawing.dll 6C879AFC7F35EC25E5E2FFF9FF0EE6EFEB155670DBFD5D0CDE9A0F629C5727B2 1.0.4.1 1.0.4.0 P3DCopyMissingObjectsToOrthoDrawing P3DCopyMissingObjectsToOrthoDrawing\P3DCopyMissingObjectsToOrthoDrawing.csproj P3DCopyMissingObjectsToOrthoDrawing v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
18 P3DNewMa.dll 97246EE9B24FD373551EF380C5AC0CA78CF7ED6A92581D5331B54445A2A948F8 1.0.4.7 1.0.4.0 P3DNewMa P3DNewMa\P3DNewMa.csproj P3DNewMa v4.7 x64 Settings.xml LIKELY_SOURCE_MATCH
19 P3DSetLayerForViewport.dll A28E58FDE4EBAA26450CA646C5A85F98C1A04AA42C0BFC5413D718243ACBF42B 1.0.4.1 1.0.4.0 P3DSetLayerForViewport P3DSetLayerForViewport\P3DSetLayerForViewport.csproj P3DSetLayerForViewport v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
20 PHPAnnotations.dll 816A693F1B775C5506043DD0461055F248D3897E96AC8285DAE29C5B71FFCA73 1.0.4.1 1.0.4.0 PHPAnnotations PHPAnnotations\PHPAnnotations.csproj PHPAnnotations v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
21 SwapAttributesMenuItem.dll 674C865E34F9C877561E03E2077F7F2C6852C3C8B6A0503ACAA7619F3E80A460 1.0.4.1 1.0.4.0 SwapAttributesMenuItem SwapAttributesMenuItem\SwapAttributesMenuItem.csproj SwapAttributesMenuItem v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
22 UpdateOrthoDrawings.dll 1492FFF1F56853DF4A858CD3E926640C1E4920B5E3F5CFCC12F4389855E630BA 1.0.4.2 1.0.4.0 UpdateOrthoDrawings UpdateOrthoDrawings\UpdateOrthoDrawings.csproj UpdateOrthoDrawings v4.7 x64 Settings.xml LIKELY_SOURCE_MATCH
23 UpdateOrthoViewBlocks.dll 5022D4D66D79E7E7D82F9FCB647DF8E1FE658A4694EB7794E363D5EA5517F5A9 1.0.4.1 1.0.4.0 UpdateOrthoViewBlocks UpdateOrthoViewBlocks\UpdateOrthoViewBlocks.csproj UpdateOrthoViewBlocks v4.7 x64 Settings.xml EXACT_SOURCE_MATCH
@@ -0,0 +1,4 @@
GeneratedUtc=2026-07-31T10:39:04.9899963Z
DeployedRoot=<network root redacted to report context>
SourceRoot=<network source root redacted to report context>
Files=52
@@ -0,0 +1,13 @@
# Legacy versus new loading model
| Legacy behavior | Legacy evidence | New implementation | Compatibility requirement | Decision | Risk |
|---|---|---|---|---|---|
| Unknown external bootstrap loads `OrthoLoader.dll` | `loading-chain.md` | Bundle bootstrap not selected yet | Identify the workstation/project startup owner first | Defer loading-model decision | High |
| 20 independent DLLs loaded in order | `Settings.xml`, `Loader.cs:63-81` | one entry assembly currently | Preserve required command availability, not the DLL count | Evaluate command/module migration individually | Medium |
| DLLs loaded from OrthoLoader's directory (possibly UNC) | `Loader.cs:49,65`; bootstrap source unknown | local smoke bundle only | Decide offline/update policy with operations owner | Do not hard-code UNC in new code | High |
| Settings.xml controls order | `Loader.cs:104-112` | MSBuild/bundle manifest currently | Preserve explicit dependency ordering where behavior requires it | Document, do not emulate blindly | Medium |
| central PluginsOrtho Ribbon | `Ribbon.cs` | new Promhimproekt tab | Preserve actual command mapping where adopted | Separate UI migration decision | Medium |
| project selection uses local app_netload.lsp | `Ribbon.cs:380-405` | no equivalent | Confirm security/project-selection policy | Do not reproduce hidden local control file | High |
| network icons and documents | `Ribbon.cs:330-357`, deployed files | bundle resources | Bundle only licensed, necessary resources | Replace network runtime dependency | Medium |
Recommendation: do not choose AppLoader or a manual-NETLOAD model yet. First identify the missing external bootstrap and confirm whether `app_netload.lsp` is the corporate launcher contract. Once confirmed, use a single versioned entry assembly with explicit manifest/dependency validation; avoid sequential programmatic NETLOAD and UNC execution because the legacy chain is non-atomic and fails the remaining modules after one error.
@@ -0,0 +1,29 @@
# Proven legacy loading chain
```text
Unknown external bootstrap
-> NETLOAD of deployed OrthoLoader.dll (not evidenced in audited directories)
-> OrthoLoader.Ribbon.Initialize()
-> subscribe ComponentManager.ItemInitialized
-> OrthoLoader.Initialize()
-> adjacent Settings.xml / Main/LoadAssemblies/LoadAssembly
-> sequential acDoc.Editor.Command("._netload", fullPath) for 20 DLLs
-> each DLL exposes CommandMethod commands
-> Ribbon ItemInitialized creates PluginsOrtho tab and command buttons
```
| Claim | Evidence | Confidence |
|---|---|---|
| Central loader is `OrthoLoader.dll` | `OrthoLoader/Ribbon.cs:151-156`; deployed DLL metadata and `Settings.xml` | High |
| Module list is read from adjacent `Settings.xml` | `OrthoLoader/Loader.cs:104-112` | High |
| Module loading is programmatic `._netload`, in XML order | `OrthoLoader/Loader.cs:63-81`; `configuration-map.csv` | High |
| Full DLL path is loader directory + configured filename | `OrthoLoader/Loader.cs:49, 65` | High |
| Modules load from the same directory as OrthoLoader | `Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)` in `Loader.cs:49,65` | High |
| Modules loaded directly from UNC | true only if external bootstrap NETLOADed the deployed UNC copy; bootstrap is outside audit scope | Unknown |
| Missing/failed module stops later loading and shows MessageBox | single outer try/catch around the loop, `Loader.cs:63-99` | High |
| Ribbon owner is OrthoLoader | `OrthoLoader/Ribbon.cs:16-19,151-172,193-321` | High |
| Initial bootstrap mechanism | no LISP/CUI/ARG/REG/PackageContents file found in either audited directory | Unknown |
`Assembly.LoadFrom` occurs inside several legacy command implementations for secondary dependencies. It is not the mechanism used by `OrthoLoader` to load its configured modules. `EnablerLoader` separately uses `Assembly.LoadFile` for the Plant enabler from the host base directory.
No `PackageContents.xml`, `*.bundle`, registry demand-load registration, LISP, CUI, MNL, script, batch, or PowerShell bootstrap was found in the audited locations. This proves absence only within audit scope; it does not prove the workstation bootstrap did not exist elsewhere.
@@ -0,0 +1,10 @@
Dependency,Category,Evidence,Requiredness,Notes
Settings.xml,CONFIGURATION,OrthoLoader/Loader.cs:104-112,Required,Adjacent to each loaded assembly directory
ico/*.png,RIBBON_RESOURCE,OrthoLoader/Ribbon.cs:330-357,Optional,Missing file yields null image
app_netload.lsp,CONFIGURATION,OrthoLoader/Ribbon.cs:380-405,Implicit,Local workstation file gates project-specific Ribbon enablement
annotation_settings.xml,REFERENCE_DATA,README.md and annotation modules,Project-dependent,Located in Plant project data area according to README
users_indexes_list.xml,REFERENCE_DATA,README.md and annotation modules,Project-dependent,Located in Plant project data area according to README
Template.dwg,TEMPLATE,Deployed inventory and legacy source references,Command-dependent,Do not treat deployed copy as approved test fixture
Plant project XML/DWG,COMMAND_TIME,UpdateOrthoDrawings and annotation source,Required by relevant command,Out of deployed plugin root
Update report CSV,LOGGING,UpdateOrthoDrawings/Commands.cs:1004,Optional,Written beside executing assembly by legacy command
Help PDFs,RIBBON_RESOURCE,P3DNewMa/NewMaControl.cs:6214,Optional,Opened from assembly directory
1 Dependency Category Evidence Requiredness Notes
2 Settings.xml CONFIGURATION OrthoLoader/Loader.cs:104-112 Required Adjacent to each loaded assembly directory
3 ico/*.png RIBBON_RESOURCE OrthoLoader/Ribbon.cs:330-357 Optional Missing file yields null image
4 app_netload.lsp CONFIGURATION OrthoLoader/Ribbon.cs:380-405 Implicit Local workstation file gates project-specific Ribbon enablement
5 annotation_settings.xml REFERENCE_DATA README.md and annotation modules Project-dependent Located in Plant project data area according to README
6 users_indexes_list.xml REFERENCE_DATA README.md and annotation modules Project-dependent Located in Plant project data area according to README
7 Template.dwg TEMPLATE Deployed inventory and legacy source references Command-dependent Do not treat deployed copy as approved test fixture
8 Plant project XML/DWG COMMAND_TIME UpdateOrthoDrawings and annotation source Required by relevant command Out of deployed plugin root
9 Update report CSV LOGGING UpdateOrthoDrawings/Commands.cs:1004 Optional Written beside executing assembly by legacy command
10 Help PDFs RIBBON_RESOURCE P3DNewMa/NewMaControl.cs:6214 Optional Opened from assembly directory
@@ -0,0 +1,9 @@
# Observed user workflow
After an external bootstrap loaded `OrthoLoader.dll`, the loader created a `PluginsOrtho` Ribbon tab only when `isProjectCorrect` accepted the current Plant project. That predicate reads the first line of the local file `C:\AutoCAD User Support\Applications\app_netload.lsp` and compares its encoded project root with the active Plant project (`OrthoLoader/Ribbon.cs:380-405`).
`PluginsOrtho` has eight panels. Button IDs are commands; clicks call `Document.SendStringToExecute(command + "\n", ...)` (`Ribbon.cs:193-321, 526-529`). Examples: `PXP-AAV` is registered by `AutoAnnotateView/Commands.cs:546`; `PXP-OA` by `OrthoAutoAnnotate/Commands.cs:6444`.
The deployed `ico/*.png` files are runtime Ribbon resources. They are resolved from the loader assembly directory; in this deployment that is the UNC directory. The code has a null-image fallback when an icon is absent.
The tab and panels use stable IDs and lookup before creation. Button collections are appended when a missing panel is created; repeated project-open events can enable existing UI or create absent UI. The event is detached after first Ribbon initialization, but `CurrentProjectOpenedEvent` is retained for the process lifetime.