Files
lmxopcua/docs/v2/implementation/phase-0-rename-and-net10.md
Joseph Doherty 5b8d708c58 Phase 0 entry gate + branch-naming convention fix
Record Phase 0 entry baseline: 820 passing, 2 pre-existing failures (Client.CLI.Tests.SubscribeCommandTests.Execute_PrintsSubscriptionMessage and Tests.MxAccess.MxAccessClientMonitorTests.Monitor_ProbeDataChange_PreventsStaleReconnect), 0 build errors, 167 build warnings. The two failures exist on v2 as of commit 1189dc8 and are unrelated to the rename. Phase 0 exit gate adapts the requirement to "failure count = baseline (2); pass count ≥ baseline (820)".

Branch-naming convention updated in implementation/overview.md and phase-0 doc: cannot use `v2/phase-N-slug` form because git treats `/` as path separator and `v2` already exists as a branch, blocking creation of any `v2/...` branch. Convention is now `phase-N-slug` (no v2/ prefix).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:46:26 -04:00

13 KiB
Raw Blame History

Phase 0 — Rename to OtOpcUa + .NET 10 Cleanup

Status: DRAFT — implementation plan for Phase 0 of the v2 build (plan.md §6).

Branch: phase-0-rename Estimated duration: 35 working days Predecessor: none (first phase) Successor: Phase 1 (phase-1-configuration-and-admin-scaffold.md)

Phase Objective

Mechanically rename the existing v1 codebase from LmxOpcUa to OtOpcUa and verify all existing v1 tests still pass under the new names. No new functionality, no .NET 10 retargeting of Host or Historian.Aveva (those move in Phase 2 with the Galaxy split — they need to stay on .NET 4.8 because of MXAccess and Wonderware Historian SDK dependencies). All other projects are already on .NET 10 and stay there.

The phase exists as a clean checkpoint: future PRs reference OtOpcUa consistently, the rename is not entangled with semantic changes, and the diff is mechanical enough to review safely.

Scope — What Changes

Concern Change
Project names ZB.MOM.WW.LmxOpcUa.*ZB.MOM.WW.OtOpcUa.* (all 11 projects)
Solution file ZB.MOM.WW.LmxOpcUa.slnxZB.MOM.WW.OtOpcUa.slnx
Namespaces ZB.MOM.WW.LmxOpcUa root → ZB.MOM.WW.OtOpcUa root (all source files)
Assembly names <AssemblyName> and <RootNamespace> in every csproj
Folder names src/ZB.MOM.WW.LmxOpcUa.*src/ZB.MOM.WW.OtOpcUa.*; same in tests/
Default appsettings.json keys Lmx*Ot* only where the section name is product-bound (e.g. LmxOpcUa.ServerOtOpcUa.Server); leave MxAccess.* keys alone (those refer to the AVEVA product, not ours)
Service registration name TopShelf service name LmxOpcUaOtOpcUa (until Phase 1 swaps TopShelf for Microsoft.Extensions.Hosting)
Documentation All docs/*.md references; CLAUDE.md
Repo name NOT in scope for Phase 0 — repo rename happens in a separate ops step after exit gate clears

Scope — What Does NOT Change

Item Reason
.NET Framework 4.8 target on Host and Historian.Aveva MXAccess COM is 32-bit only; Wonderware Historian SDK is .NET 4.8. Both move to Galaxy.Host (still .NET 4.8 x86) in Phase 2.
.NET 10 target on Client.CLI / Client.Shared / Client.UI / all Tests Already there (verified 2026-04-17 via grep TargetFramework src/*/*.csproj).
Project structure (no new projects) New projects (Configuration, Core, Core.Abstractions, Server, Admin) are added in Phase 1, not Phase 0.
Galaxy / MXAccess implementation Stays in OtOpcUa.Host for now; Phase 2 splits it into Proxy/Host/Shared.
master branch / production deployments Untouched — v2 work all happens on the v2 branch.
OPC UA ApplicationUri defaults Currently include LmxOpcUa — leave as-is to avoid breaking existing client trust during v1/v2 coexistence. New ApplicationUri defaults land in Phase 1 alongside the cluster model.
MxAccess product references in docs / code "MxAccess" is AVEVA's product name, not ours. Stays.

Entry Gate Checklist

Verify all before opening the phase-0-rename branch:

  • v2 branch is at commit a59ad2e or later (decisions #1125 captured)
  • git status is clean on v2
  • dotnet test ZB.MOM.WW.LmxOpcUa.slnx passes locally with zero failing tests, baseline test count recorded
  • dotnet build ZB.MOM.WW.LmxOpcUa.slnx succeeds with zero errors and ≤ baseline warning count
  • All design docs reviewed by the implementation lead: docs/v2/plan.md, docs/v2/config-db-schema.md, docs/v2/admin-ui.md, docs/v2/driver-specs.md, docs/v2/driver-stability.md, docs/v2/implementation/overview.md
  • Decision #9 (rename to OtOpcUa as step 1) re-read and confirmed
  • No other developers have open work on v2 that would conflict with bulk renames

Evidence file: docs/v2/implementation/entry-gate-phase-0.md recording date, baseline test count, signoff name.

Task Breakdown

Task 0.1 — Inventory references

Generate a complete map of every place LmxOpcUa appears:

grep -rln "LmxOpcUa" --include="*.cs" --include="*.csproj" --include="*.slnx" --include="*.json" --include="*.md" --include="*.razor" .

Save the result to docs/v2/implementation/phase-0-rename-inventory.md (gitignored after phase completes).

Acceptance:

  • Inventory file exists, lists every reference grouped by file type
  • Reviewer agrees inventory is complete (cross-check against git grep -i lmx for case-sensitivity bugs)

Task 0.2 — Rename project folders

Per project (11 projects total — 5 src + 6 tests):

git mv src/ZB.MOM.WW.LmxOpcUa.Client.CLI src/ZB.MOM.WW.OtOpcUa.Client.CLI
git mv src/ZB.MOM.WW.OtOpcUa.Client.CLI/ZB.MOM.WW.LmxOpcUa.Client.CLI.csproj \
       src/ZB.MOM.WW.OtOpcUa.Client.CLI/ZB.MOM.WW.OtOpcUa.Client.CLI.csproj

Repeat for: Client.Shared, Client.UI, Historian.Aveva, Host, and all 6 test projects.

Use git mv (not mv + git rm/git add) to preserve history.

Acceptance:

  • ls src/ shows only ZB.MOM.WW.OtOpcUa.* folders
  • ls tests/ shows only ZB.MOM.WW.OtOpcUa.* folders
  • git log --follow on a renamed file shows continuous history pre-rename

Task 0.3 — Rename solution file

git mv ZB.MOM.WW.LmxOpcUa.slnx ZB.MOM.WW.OtOpcUa.slnx

Edit the .slnx to update every project path reference inside it.

Acceptance:

  • ZB.MOM.WW.OtOpcUa.slnx exists and references the renamed project paths
  • dotnet sln list (or dotnet build against the slnx) succeeds

Task 0.4 — Update csproj contents

For every csproj:

  • Update <AssemblyName> if explicitly set
  • Update <RootNamespace> if explicitly set
  • Update <ProjectReference Include=...> paths for inter-project refs
  • Update <PackageId> if any project ships as a NuGet (none currently expected, but verify)

Acceptance:

  • grep -rl "LmxOpcUa" src/*/*.csproj tests/*/*.csproj returns empty
  • dotnet restore succeeds with no missing project references

Task 0.5 — Bulk-rename namespaces in source files

Run the rename across all .cs and .razor files:

grep -rl "ZB.MOM.WW.LmxOpcUa" --include="*.cs" --include="*.razor" . \
  | xargs sed -i 's/ZB\.MOM\.WW\.LmxOpcUa/ZB.MOM.WW.OtOpcUa/g'

Acceptance:

  • grep -rln "ZB.MOM.WW.LmxOpcUa" --include="*.cs" --include="*.razor" . returns empty
  • dotnet build ZB.MOM.WW.OtOpcUa.slnx succeeds

Task 0.6 — Update appsettings.json + service hosting

In src/ZB.MOM.WW.OtOpcUa.Host/appsettings.json and equivalents:

  • Rename product-named sections: LmxOpcUa.ServerOtOpcUa.Server (if present)
  • Leave MxAccess, Galaxy, Historian keys untouched (those are external product names)
  • Update TopShelf ServiceName constant from LmxOpcUaOtOpcUa

Acceptance:

  • Service install (dotnet run --project src/.../Host install) registers as OtOpcUa
  • Service uninstall + reinstall cycle succeeds on a Windows test box

Task 0.7 — Update documentation references

  • CLAUDE.md: replace LmxOpcUa references with OtOpcUa in product-naming contexts; leave MxAccess / MXAccess references alone
  • docs/*.md (existing v1 docs): same pattern
  • docs/v2/*.md: already uses OtOpcUa — verify with grep

Acceptance:

  • grep -rln "LmxOpcUa" docs/ CLAUDE.md returns only references that explicitly need to retain the old name (e.g. historical sections, change log)
  • Each retained reference has a comment explaining why

Task 0.8 — Run full test suite + smoke test

dotnet build ZB.MOM.WW.OtOpcUa.slnx
dotnet test ZB.MOM.WW.OtOpcUa.slnx

Plus manual smoke test of Client.CLI against a running v1 OPC UA server:

dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- connect -u opc.tcp://localhost:4840
dotnet run --project src/ZB.MOM.WW.OtOpcUa.Client.CLI -- browse -u opc.tcp://localhost:4840 -r -d 2

Acceptance:

  • Test count matches the baseline recorded at entry gate; zero failing tests
  • Smoke test produces equivalent output to baseline (capture both, diff)

Task 0.9 — Update build commands in CLAUDE.md

The Build Commands section currently references ZB.MOM.WW.LmxOpcUa.slnx. Update to ZB.MOM.WW.OtOpcUa.slnx. Also update test paths.

Acceptance:

  • cat CLAUDE.md | grep -i lmxopcua returns only retained-by-design references
  • A new developer cloning the repo can follow CLAUDE.md to build + test successfully

Compliance Checks (run at exit gate)

A phase-0-compliance.ps1 (or .sh) script runs all these and exits non-zero on any failure:

  1. No stale LmxOpcUa references:

    grep -rln "LmxOpcUa" --include="*.cs" --include="*.csproj" --include="*.slnx" \
      --include="*.json" --include="*.razor" . | wc -l
    

    Expected: 0 (or only allowlisted retained references)

  2. All projects build:

    dotnet build ZB.MOM.WW.OtOpcUa.slnx --warnaserror
    

    Expected: success, warning count ≤ baseline

  3. All tests pass:

    dotnet test ZB.MOM.WW.OtOpcUa.slnx
    

    Expected: total count = baseline, failures = 0

  4. Solution structure matches plan:

    • ls src/ shows exactly: ZB.MOM.WW.OtOpcUa.{Client.CLI, Client.Shared, Client.UI, Historian.Aveva, Host} (5 entries)
    • ls tests/ shows the 6 test projects similarly renamed
    • No new projects yet (those land in Phase 1)
  5. .NET targets unchanged:

    • Client projects (CLI/Shared/UI): net10.0
    • Host + Historian.Aveva: net48 (split + retarget happens Phase 2)
    • All test projects: same targets as their SUT projects
  6. Decision compliance: this phase implements decision #9 ("Rename to OtOpcUa as step 1"). Verify by:

    grep -rln "decision #9\|Decision #9" src/ tests/
    

    Expected: at least one citation in CLAUDE.md or a phase-rename README explaining the mechanical scope.

  7. Service registration works:

    • Install service → sc query OtOpcUa returns the service
    • Uninstall service → sc query OtOpcUa returns "service does not exist"

Behavioral Smoke Test (exit-gate gate)

The v1 IntegrationTests suite is the authoritative behavioral spec for Phase 0. The renamed code must pass it identically.

dotnet test tests/ZB.MOM.WW.OtOpcUa.IntegrationTests --logger "console;verbosity=detailed"

Expected: pass count = baseline. Fail count = 0. Skipped count = baseline.

Completion Checklist

The exit gate signs off only when every item below is checked:

  • All 11 projects renamed (5 src + 6 tests)
  • Solution file renamed
  • All <AssemblyName> / <RootNamespace> / <ProjectReference> updated
  • All namespaces in source files updated
  • appsettings.json product-named sections updated; external product names untouched
  • TopShelf service name updated; install/uninstall cycle verified on a Windows host
  • docs/*.md and CLAUDE.md references updated; retained references explained
  • Build succeeds with zero errors and warning count ≤ baseline
  • Test suite passes with zero failures and count = baseline
  • Smoke test against running OPC UA server matches baseline output
  • phase-0-compliance.ps1 script runs and exits 0
  • Adversarial review of the phase diff (/codex:adversarial-review --base v2) — findings closed or deferred with rationale
  • PR opened against v2, includes: link to this doc, link to exit-gate record, compliance script output, adversarial review output
  • Reviewer signoff (one reviewer beyond the implementation lead)
  • exit-gate-phase-0.md recorded with all of the above

After the PR merges, repo rename (lmxopcuaotopcua on Gitea) happens as a separate ops step — out of scope for Phase 0.

Risks and Mitigations

Risk Likelihood Impact Mitigation
Bulk sed rename breaks string literals (e.g. "LmxOpcUa" used as a runtime identifier) Medium Medium Inventory step (0.1) flags string literals separately; rename them deliberately, not via bulk sed
MxAccess / Galaxy / Wonderware references accidentally renamed Low High (breaks COM interop) Inventory step (0.1) calls out external product names explicitly; bulk rename targets only ZB.MOM.WW.LmxOpcUa (with namespace prefix), not bare LmxOpcUa
Test count drops silently because a test project doesn't get re-discovered Medium High Baseline test count captured at entry gate; exit gate compares exactly
.slnx references break and projects disappear from solution view Low Medium dotnet sln list after Task 0.3 verifies all projects load
TopShelf service install fails on a hardened Windows box (UAC, signing) Low Low Manual install/uninstall cycle is part of Task 0.6 acceptance
Long-lived branches diverge while phase 0 is in flight Medium Low Phase 0 expected duration ≤ 5 days; coordinate that no other v2 work merges during the phase

Out of Scope (do not do in Phase 0)

  • Adding any new project (Configuration, Admin, Core, Server, Driver.* — all Phase 1+)
  • Splitting Host into Galaxy.Proxy/Host/Shared (Phase 2)
  • Migrating Host/Historian.Aveva to .NET 10 (Phase 2 — when Galaxy is split, the .NET 4.8 x86 piece becomes Galaxy.Host and the rest can move)
  • Replacing TopShelf with Microsoft.Extensions.Hosting (Phase 1, decision #30)
  • Implementing the cluster / namespace / equipment data model (Phase 1)
  • Changing any OPC UA wire behavior
  • Renaming the Gitea repo