69 lines
4.7 KiB
Markdown
69 lines
4.7 KiB
Markdown
# v3 Batch 1 — greenfield schema + RawPath identity rewiring
|
||
|
||
**Branch:** `v3/batch1-schema-identity` → `master`
|
||
**Plan:** `docs/plans/2026-07-15-v3-batch1-schema-identity-plan.md` · **Design:** `docs/plans/2026-07-15-raw-uns-two-subtree-v3-design.md`
|
||
|
||
Greenfield, compatibility-breaking. The config schema and every identity seam now speak **RawPath**
|
||
(`<Folder/…>/<Driver>/<Device>/<TagGroup/…>/<Tag>`). The full solution builds and all macOS-safe
|
||
tests pass; the OPC UA address space is **deliberately dark** (drivers connect, no tag variables
|
||
materialize) until Batch 4.
|
||
|
||
## What changed
|
||
|
||
- **Schema (greenfield):** new `RawFolder` / `TagGroup` / `UnsTagReference`; reshaped `DriverInstance`
|
||
(−`NamespaceId`, +`RawFolderId?`), `Tag` (raw-only: req `DeviceId`, +`TagGroupId?`,
|
||
−`DriverInstanceId`/`EquipmentId`/`FolderPath`, kept `WriteIdempotent`), `Equipment` (−driver/device
|
||
binding); `Namespace` / `NamespaceKind` / `EquipmentImportBatch` retired. Single squashed `V3Initial`
|
||
migration (stored procs audited — the vestigial generation-model procs were rewritten to v3-valid
|
||
stubs; `sp_ComputeGenerationDiff` diffs the new tables).
|
||
- **Identity:** new `Commons/Types/RawPaths.cs` helper; `TagConfigIntent` sheds `FullName`;
|
||
`EquipmentTagRefResolver<TDef>` is byName(RawPath)-only (blob-fallback deleted); new
|
||
`RawTagEntry(RawPath, TagConfig, WriteIdempotent, DeviceName)` delivery record. All 8 drivers
|
||
re-keyed: the per-driver `*EquipmentTagParser` became `*TagDefinitionFactory.FromTagConfig`, options
|
||
`Tags` → `RawTags`, `TagConfig` key normalization (`nodeId` / `attributeRef`; `deviceHostAddress`
|
||
dropped).
|
||
- **Endpoint → DeviceConfig:** new `DriverDeviceConfigMerger` (Commons) merges DriverConfig + per-device
|
||
DeviceConfig; multi-device drivers reconstruct their `Devices[]` from Device rows; the artifact injects
|
||
the merged config + `rawTags` at spawn.
|
||
- **Pipeline:** `ConfigComposer` snapshots the new tables; `DeploymentArtifact` flattens per-driver
|
||
`RawTagEntry` lists keyed by RawPath (via `RawPathResolver`) + emits an empty (dark) equipment-tag
|
||
plan set; `AddressSpaceComposer`/walker compose folders + VirtualTags + ScriptedAlarms only;
|
||
`DriverHostActor` maps re-keyed to RawPath; `DraftValidator` gains `RawNameInvalid` /
|
||
`HistorianTagnameTooLong` / `UnsEffectiveNameCollision`.
|
||
- **AdminUI (compile-only stubs):** Namespace pages → retired banners; driver pages dropped the
|
||
pre-declared Tags editor + NamespaceId; `UnsTreeService` tag-authoring returns "moved to the Raw tree
|
||
(/raw) in v3 Batch 2". (Batch 2/3 build the real `/raw` + reference UI.)
|
||
|
||
## Verification gate (all four items)
|
||
|
||
1. **Build + test green.** Full solution builds (0 errors). macOS-safe unit suites: Commons 196,
|
||
Core 260, Core.Abstractions 134, **Configuration 107**, Runtime 355 (42 dark-Batch-4 skips),
|
||
ControlPlane 78, OpcUaServer 335 (4 skips), AdminUI 507 (3 skips), + all 8 driver unit suites
|
||
(Modbus 315, S7 264, AbCip 342, AbLegacy 213, TwinCAT 192, FOCAS 272, OpcUaClient 138, Galaxy 313)
|
||
and the 6 driver IntegrationTests projects compile. Enum-serialization round-trip coverage preserved.
|
||
2. **Fresh-DB migration.** `V3Initial` applies clean to a scratch DB; `SchemaComplianceTests` 8/8.
|
||
3. **docker-dev boot (live).** Volume wiped → `V3Initial` applied → both central nodes reached Akka
|
||
Up → a seeded Modbus driver **spawned and connected** to the `10.100.0.35:5020` fixture
|
||
(`DriverInstance MAIN-modbus: connected`), deployment **sealed (acks=2)**; AdminUI HTTP 200 on
|
||
`/`, `/clusters`, `/uns` with 0 unhandled exceptions.
|
||
4. **Dark address space (Client.CLI browse).** Recursive browse of `opc.tcp://localhost:4840`: the raw
|
||
tag `HR200` and the driver have **0 occurrences**; the custom namespace `ns=2` holds only the empty
|
||
`OtOpcUa` root — no authored variables materialize (Batch 4 lights them up).
|
||
|
||
## AdminUI Batch-1 stubs (Batch 2/3 replace)
|
||
|
||
Namespace pages (`NamespaceEdit`, `ClusterNamespaces`) → banners; the 8 driver pages' pre-declared Tags
|
||
editors + Namespace bindings removed; `DriverIdentitySection` Namespace dropdown removed;
|
||
`UnsTreeService.CreateTagAsync`/`UpdateTagAsync` return the "moved to /raw" failure; per-equipment tag
|
||
lists empty.
|
||
|
||
## Deferred (owned by later batches, not regressions)
|
||
|
||
- `/raw` project tree + reference-picker UI, dual `ns=Raw`/`ns=UNS` namespaces + tag-variable
|
||
materialization, `{{equip}}` reference-relative resolution — Batches 2–4 (address space intentionally
|
||
dark now).
|
||
- User-facing docs beyond the `Configuration.md` v3 note (they describe the not-yet-built UI/address
|
||
space) — updated as Batches 2–4 land.
|
||
- Live driver IntegrationTests + one pre-existing `AbCip_Green_AgainstSim` fixture-probe failure
|
||
(AB CIP sim handshake — environment/fixture gate, untouched).
|