Commit Graph

275 Commits

Author SHA1 Message Date
Joseph Doherty 77024f87da fix(uns): reject tag create on non-existent equipment + narrow JSON catch (review) 2026-06-08 13:06:45 -04:00
Joseph Doherty 5a392c5db0 feat(uns): equipment-bound tag CRUD with namespace + cluster guards 2026-06-08 13:00:26 -04:00
Joseph Doherty ab0ff8aedf fix(uns): reject driver-bind on unresolvable line + enforce MachineCode uniqueness on update (review) 2026-06-08 12:55:36 -04:00
Joseph Doherty 2836a0704b feat(uns): equipment CRUD with #122 driver-cluster guard 2026-06-08 12:47:19 -04:00
Joseph Doherty 8b1d3de806 feat(uns): add global UNS nav item, drop per-cluster UNS/Equipment/Tags tabs 2026-06-08 12:45:18 -04:00
Joseph Doherty 4a32edef1a fix(uns): re-entrancy guard + clear stale error + PageTitle on GlobalUns (review) 2026-06-08 12:39:23 -04:00
Joseph Doherty 47b1d2259f feat(uns): area + line CRUD with #122 reassignment guard 2026-06-08 12:35:58 -04:00
Joseph Doherty c9f59e4bd2 feat(uns): GlobalUns page with browsable tree 2026-06-08 12:34:37 -04:00
Joseph Doherty b33cf1c80d feat(uns): lazy per-equipment tag + virtual-tag load
Add LoadEquipmentChildrenAsync to IUnsTreeService and UnsTreeService; returns
Tag nodes (ordered by Name) then VirtualTag nodes (ordered by Name) as leaf
nodes with ChildCount=0, HasLazyChildren=false, keys tag:{id}/vtag:{id}.
2026-06-08 12:29:52 -04:00
Joseph Doherty c264441b74 refactor(uns): clarify service lifetime doc + defensive vtag-count null filter (review) 2026-06-08 12:27:29 -04:00
Joseph Doherty 2c0297c1af fix(uns): @key node rows for stable Blazor diffing (review) 2026-06-08 12:27:19 -04:00
Joseph Doherty cec670f0c8 feat(uns): IUnsTreeService structural load + DI registration 2026-06-08 12:23:00 -04:00
Joseph Doherty 0f286a70b8 feat(uns): recursive UnsTree renderer 2026-06-08 12:21:38 -04:00
Joseph Doherty 3e8941bce4 docs(uns): clarify HasLazyChildren + cluster EntityId, add tie-break test (review I1/I2/M2) 2026-06-08 12:18:37 -04:00
Joseph Doherty d9082e22e3 feat(uns): UnsNode VM + pure tree-assembly helper 2026-06-08 12:14:49 -04:00
Joseph Doherty f5ef0991af docs(adminui): correct equipment help text for driver-less equipment (review I1/M1)
v2-ci / build (push) Failing after 4m24s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
2026-06-08 07:13:45 -04:00
Joseph Doherty d909a8e4f6 docs+test(deploy): clarify driver-less attribution docs + no-line exclusion test (Task 2 review) 2026-06-08 07:02:25 -04:00
Joseph Doherty 0b5fc44866 fix(adminui): show + clarify driver-less equipment across list/import (Task 1 review) 2026-06-08 07:00:03 -04:00
Joseph Doherty c688899134 fix(deploy): cluster-attribute driver-less equipment via its UNS line area (BuildClusterSets) 2026-06-08 06:53:41 -04:00
Joseph Doherty d2dbf7b0d7 feat(config): make Equipment.DriverInstanceId nullable + driver-less AdminUI support + migration 2026-06-08 06:49:28 -04:00
Joseph Doherty 92d1df88f4 fix(deploy): guardrail estimate is best-effort, never blocks a valid deploy
Wrap the script compile-cost guardrail block in its own inner try/catch so a
transient SQL failure on ToListAsync cannot fall through to the outer catch and
produce a Rejected reply for an otherwise-valid deploy. advisory is declared in
the outer scope so the Accepted StartDeploymentResult Message is unaffected on
the happy path; the inner catch logs a Warning and leaves advisory null.
2026-06-07 15:40:06 -04:00
Joseph Doherty cfbf0b2a17 feat(deploy): warn-only script-compile-cost advisory on deploy 2026-06-07 15:36:09 -04:00
Joseph Doherty 08d7477860 feat(vtag): passthrough fast-path skips Roslyn for mirror scripts (A) 2026-06-07 15:26:20 -04:00
Joseph Doherty f078d41a8b test(deploy): cover cross-cluster rejection through the actor; note reservation false-positive at gate
v2-ci / build (push) Failing after 42s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
2026-06-07 11:28:17 -04:00
Joseph Doherty 2676fc17b5 fix(host): pin EF/AspNetCore logs to Warning in appsettings.Development 2026-06-07 11:19:26 -04:00
Joseph Doherty 5aba418074 feat(deploy): activate full DraftValidator gate (reject on any validation error) 2026-06-07 11:19:23 -04:00
Joseph Doherty 1023209d52 feat(deploy): reject Tag/VirtualTag NodeId collisions at deploy (surgical DraftValidator gate) 2026-06-07 10:42:13 -04:00
Joseph Doherty 6b36eff2d3 refactor(runtime): capture-first in HandleWriteAsync; assert no handler leak on resubscribe; fix stale comment 2026-06-07 10:31:20 -04:00
Joseph Doherty 98259ab026 fix(runtime): capture Sender before await in DriverInstanceActor subscribe (no-ActorContext race) 2026-06-07 10:26:17 -04:00
Joseph Doherty 4c221ce2b3 merge: equipment-namespace live values (VirtualTag route)
v2-ci / build (push) Failing after 36s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
2026-06-07 09:33:21 -04:00
Joseph Doherty 1c579410cd fix(runtime): flag cross-cluster orphan-equipment bindings on rebuild
v2-ci / build (push) Failing after 42s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
ParseComposition(blob, nodeId, onInconsistency?) detects a kept equipment whose
UNS line belongs to another cluster (a same-cluster-invariant violation that
would orphan the equipment folder) and reports it via an optional callback,
wired to OpcUaPublishActor's logger. Detection-only; the upstream draft
validator remains the authority. Adds two unit tests.
2026-06-07 08:24:11 -04:00
Joseph Doherty 1f76eac97a fix(controlplane): case-insensitive NodeId equality for deploy ack-set
Aligns ConfigPublishCoordinator's _acks/_expectedAcks with the case-insensitive
ClusterId/NodeId scoping in DeploymentArtifact.ResolveClusterScope, so an ack
from a node whose host:port differs only in case still matches its expected-ack
entry (SQL collation + DNS are case-insensitive).
2026-06-07 08:20:56 -04:00
Joseph Doherty 984ef79c1f docs(opcua): correct EquipmentVirtualTagPlan equality comment (element-wise, not by-ref) 2026-06-07 06:11:56 -04:00
Joseph Doherty 2bfe18abcf chore(runtime): warn on missing VirtualTag evaluator; document Stale-recovery VirtualTag behaviour
Log a WARNING on startup when IVirtualTagEvaluator is not registered so a DI misconfig on a
driver-role node is visible in logs instead of silently evaluating all VirtualTags to NoChange.
Add a comment in PushDesiredSubscriptions noting that TryRecoverFromStale does not call this
method, so VirtualTags remain empty after a Stale recovery until the next deployment dispatch
(intentional, consistent with driver recovery).
2026-06-07 05:46:24 -04:00
Joseph Doherty 397f9b783a feat(runtime): spawn+apply VirtualTagHostActor on deploy apply and restore 2026-06-07 05:41:04 -04:00
Joseph Doherty 5e2869bab7 fix(runtime): VirtualTagHost watches children + respawns after unexpected death
Context.Watch each spawned child; OnChildTerminated evicts it from _children so the
next ApplyVirtualTags (still containing that vtagId) falls through the ContainsKey
guard and re-spawns a fresh VirtualTagActor.  Adds a spawn-site Debug log, moves the
TODO about in-place plan mutation to the skip-existing branch where it belongs, and
adds a deterministic TestKit test (Child_is_respawned_after_unexpected_termination)
that kills the first child, drains its UnregisterInterest from the mux probe, re-applies,
and asserts a second distinct RegisterInterest arrives.
2026-06-07 05:34:50 -04:00
Joseph Doherty 85a36cec54 feat(runtime): VirtualTagHostActor spawns VTag actors + bridges results to OPC UA 2026-06-07 05:28:46 -04:00
Joseph Doherty 695e61dedf feat(opcua): materialise Equipment VirtualTag variables on rebuild 2026-06-07 05:22:22 -04:00
Joseph Doherty 9818d0cba8 fix(opcua): structural equality for EquipmentVirtualTagPlan so no-op redeploys diff empty
IReadOnlyList<string> DependencyRefs compared by reference in the auto-generated record
equality, causing every VirtualTag with dependencies to be flagged "Changed" on every parse
(fresh list instances from composer and artifact-decoder). Add Equals/GetHashCode overrides
with element-wise ordinal comparison so Phase7Plan.IsEmpty short-circuits a no-op redeploy.
Add regression test Identical_virtualtag_snapshots_diff_to_empty_plan (separate list instances,
same contents → IsEmpty true). Add TODO comment in Phase7Applier near needsRebuild predicate.
2026-06-07 05:19:47 -04:00
Joseph Doherty 9464c91546 feat(opcua): diff Equipment VirtualTags in Phase7Plan + rebuild trigger 2026-06-07 05:15:21 -04:00
Joseph Doherty c7661d0510 feat(opcua): parse Equipment VirtualTag plans from the deployment artifact 2026-06-07 05:09:53 -04:00
Joseph Doherty 1a60c0199c test(opcua): cover missing-script fallback; rename composer local for clarity 2026-06-07 05:04:41 -04:00
Joseph Doherty ae14d98658 feat(opcua): compose Equipment VirtualTag plans from VirtualTag+Script rows 2026-06-07 04:54:36 -04:00
Joseph Doherty 45fa198494 feat(opcua): add EquipmentVirtualTagPlan to Phase7 composition
Adds the EquipmentVirtualTagPlan sealed record (VirtualTagId, EquipmentId,
FolderPath, Name, DataType, Expression, DependencyRefs) and the
EquipmentVirtualTags init-only member on Phase7CompositionResult, mirroring
the existing EquipmentTagPlan / EquipmentTags pattern. Type-only: no producer
logic yet. Two new tests cover the default-empty guarantee and the record shape.
2026-06-07 04:51:14 -04:00
Joseph Doherty 8ce57e47a3 feat(runtime): OPC UA rebuild materialises only the node's ClusterId slice 2026-06-07 03:23:02 -04:00
Joseph Doherty 1b7f995aea feat(runtime): DriverHost spawns + subscribes only its own ClusterId's drivers 2026-06-07 03:19:22 -04:00
Joseph Doherty 4fca4e1aca feat(runtime): node-scoped ParseComposition filters address space by ClusterId 2026-06-07 03:15:46 -04:00
Joseph Doherty 7b2f64fdb8 refactor(runtime): case-insensitive ClusterId/NodeId match + suppress short-circuit + edge tests (review) 2026-06-07 03:12:09 -04:00
Joseph Doherty 24796f2c12 feat(runtime): ClusterId scope resolution + node-scoped driver-spec parse 2026-06-07 03:05:02 -04:00
Joseph Doherty ad7f9e731f feat(admin): headless POST /api/deployments REST endpoint (API-key gated)
v2-ci / build (push) Failing after 50s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
A thin gateway over the admin-operations cluster singleton so CI/scripts can trigger a
deployment without the Blazor button. Forwards to the same IAdminOperationsClient.
StartDeploymentAsync; mounted on admin-role nodes. Auth is a fixed-time X-Api-Key check
against Security:DeployApiKey (orthogonal to the cookie-only web auth); AllowAnonymous so the
auth fallback doesn't 401 it, self-disabling (503) until the key is set. Outcome->status:
202/200/409/422. Unit tests for the key check + outcome mapping; HTTP E2E (real auth + real
deploy via the 2-node harness). Documented in docs/security.md.
2026-06-06 15:54:51 -04:00