{ "planPath": "docs/plans/2026-06-01-deploy-zb-configuration.md", "tasks": [ {"id": 11, "subject": "Task 1: Foundation — publish package + wire 3 consumers", "classification": "small", "status": "completed", "result": "Published ZB.MOM.WW.Configuration 0.1.0 to Gitea (was 404; now 200). nuget.config source-mapping + version pins on feat/adopt-zb-configuration in all 3 repos. Commits: MxGw 437ab65, OtOpcUa 0cbb82e, ScadaBridge 9bca6aa."}, {"id": 12, "subject": "Task 2: MxGateway — GatewayOptionsValidator → base", "classification": "standard", "status": "completed", "blockedBy": [11], "commit": "459a88b", "result": "Migrated to OptionsValidatorBase via RequireThat (messages byte-identical); AddGatewayConfiguration → AddValidatedOptions (+4 call sites). Tests 571/574 (3 pre-existing macOS failures). Spec ✅, code Approved-with-minors."}, {"id": 13, "subject": "Task 3: OtOpcUa — net-new LdapOptionsValidator", "classification": "standard", "status": "completed", "blockedBy": [12], "commit": "f35ebd7", "result": "New LdapOptionsValidator; Program.cs:99 → AddValidatedOptions(config,'Ldap') — behaviour-preserving per user decision A. FLAG: OtOpcUa LDAP binds nonexistent sections (real config = Security:Ldap); recorded as memory otopcua-ldap-config-section-mismatch. 4/4 new tests; build 0/0."}, {"id": 14, "subject": "Task 4: OtOpcUa — OpcUa validator + DI routing", "classification": "high-risk", "status": "completed", "blockedBy": [12], "commit": "88e773a", "result": "New OpcUaApplicationHostOptionsValidator; AddValidatedOptions(config,'OpcUa') in hasDriver block; hosted service now consumes IOptions (dead _configuration removed). 4/4 new tests; build 0/0. Spec ✅, code Approved-with-minors."}, {"id": 15, "subject": "Task 5: ScadaBridge — 4 validators → base", "classification": "standard", "status": "completed", "blockedBy": [13, 14], "commit": "aac59c9", "result": "Cluster/Security/HealthMonitoring/AuditLog → OptionsValidatorBase via RequireThat (no primitives; messages verbatim). DI untouched (AddValidatedOptions collapse deferred). 33/33 validator tests unchanged. Spec ✅, code Approved-with-minors (De Morgan readability nits)."}, {"id": 16, "subject": "Task 6: ScadaBridge — StartupValidator → ConfigPreflight", "classification": "high-risk", "status": "completed", "blockedBy": [13, 14], "commit": "6dbbc7a", "result": "StartupValidator body re-implemented over ConfigPreflight (Require escape-hatch for bespoke + cross-field rules; default int.TryParse + IsNullOrEmpty preserved). StartupValidatorTests 46/46 UNCHANGED (byte-compat proof). Spec ✅, code Approved-with-minors."} ], "deferred": [ "ScadaBridge: collapse module AddXxx → AddValidatedOptions (DI simplification; preserve HealthMonitoring idempotent registration).", "MxGateway pre-existing (not regressions): Ldap:Port allows >65535; AddIfInvalidPath doesn't catch IOException.", "OtOpcUa pre-existing bug (flagged + memory): LdapOptions binds Security:Ldap nowhere; DevStubMode never applies — separate behaviour-changing fix.", "Cosmetic: De Morgan predicate comments (ScadaBridge validators); vestigial `var options = _options` in OtOpcUaServerHostedService." ], "lastUpdated": "2026-06-01" }