Commit Graph

2168 Commits

Author SHA1 Message Date
Joseph Doherty 12b3206555 Merge R2-05 AdminUI authorization (arch-review round 2) [PR #428]
v2-ci / build (push) Successful in 3m27s
v2-ci / unit-tests (push) Failing after 8m29s
Finding 04/C-1 (High): explicit named-policy gating on all 38 AdminUI pages via
new AdminUiPolicies (ConfigEditor + AuthenticatedRead) + anti-drift reflection
guard. T15 live pass deferred (docker-dev auto-admin can't observe deny).
STATUS.md conflict resolved additively. Build clean.
2026-07-13 10:12:57 -04:00
Joseph Doherty 479057097a Merge R2-06 ServerHistorian fail-fast + 0.2.0 DataType (arch-review round 2) [PR #427]
v2-ci / build (push) Successful in 3m15s
v2-ci / unit-tests (push) Failing after 8m17s
Findings 06/S-11 (fail-fast ServerHistorianOptionsValidator, no UriFormatException
crash-loop), 06/U-7 (0.2.0 Boolean->Int1 explicit-presence + retype probe),
06/C-7 (keep-populating decision doc). T12 live VPN gate deferred. STATUS.md conflict
(R2-12 bookkeeping) resolved additively. Build clean.
2026-07-13 10:10:48 -04:00
Joseph Doherty d59e6b5934 docs(r2-06): mark T12 live gate deferred-live + record execution deviations (06/U-7)
v2-ci / build (pull_request) Successful in 3m55s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (pull_request) Failing after 3m51s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (pull_request) Failing after 1m43s
v2-ci / unit-tests (pull_request) Failing after 8m36s
2026-07-13 10:07:37 -04:00
Joseph Doherty 6c1f05cba9 docs(r2-05): flip 04/C-1 to FIXED, record execution deviations + task status
v2-ci / build (pull_request) Successful in 3m50s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (pull_request) Failing after 3m35s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (pull_request) Failing after 1m42s
v2-ci / unit-tests (pull_request) Failing after 9m55s
2026-07-13 10:07:27 -04:00
Joseph Doherty fc38cee00e docs(r2-06): record S-11/U-7/C-7 remediation in STATUS.md + 06 report rows (06/S-11,U-7,C-7) 2026-07-13 10:07:00 -04:00
Joseph Doherty 3c81f6ebf8 Merge R2-12 repo hygiene (arch-review round 2) [PR #426]
v2-ci / build (push) Successful in 3m21s
v2-ci / unit-tests (push) Failing after 8m24s
Findings 07/U-3/4/5/6, S-3, P-5, C-4/5/6: remove orphaned AVEVA lib/ DLLs,
untrack/archive planning files, delete no-op E2E workflow + redundant CI job,
document alarm CLI commands, xunit pin hygiene. Isolated; clean build.
2026-07-13 10:06:17 -04:00
Joseph Doherty 4640ecb19b docs(r2-06): note WriteLiveValues Quality is a documented-dead input (0.2.0 C-002); keep 192 populated (06/C-7) 2026-07-13 10:04:29 -04:00
Joseph Doherty 1455550d0c chore(r2-12): mark T11 final verification complete
v2-ci / build (pull_request) Successful in 3m22s
v2-ci / unit-tests (pull_request) Failing after 8m31s
2026-07-13 10:02:53 -04:00
Joseph Doherty 04a9edab7e docs(r2-12): record R2-12 repo-hygiene execution + open follow-ups in STATUS.md 2026-07-13 10:02:38 -04:00
Joseph Doherty e5cf986a10 docs(r2-06): 0.2.0 DataType provisioning delta (upsert/retype) + HISTGW_BOOL_SANDBOX_TAG recipe (06/U-7) 2026-07-13 10:02:37 -04:00
Joseph Doherty dad783514a docs(security): document AdminUI policy tiers (ConfigEditor/AuthenticatedRead) + R2-05 status 2026-07-13 10:01:52 -04:00
Joseph Doherty 152d8ebe0e test(r2-12): document + patch-align the xunit v2 holdout pin (07/C-4)
Branch B (upstream-blocked): probed nuget.org for an xunit.v3 Akka TestKit —
Akka.TestKit.Xunit3 and Akka.TestKit.Xunit.v3 both return BlobNotFound (verified
2026-07-13), so the 3 holdouts (AdminUI/ControlPlane/Runtime.Tests) cannot migrate
off xunit v2 yet. Bumped the pin 2.9.2 -> 2.9.3 (latest 2.9.x) and moved the blocker
rationale + removal condition to a comment at the pin in Directory.Packages.props so
it lives at the version, not just in 3 scattered csprojs. All 3 suites green on 2.9.3
(514 + 63 + 364 tests).
2026-07-13 10:01:12 -04:00
Joseph Doherty 1aa89d754f test(r2-06): HISTGW_BOOL_SANDBOX_TAG fixture + Boolean EnsureTags leg + retype probe (skip-clean offline) (06/U-7) 2026-07-13 10:01:12 -04:00
Joseph Doherty aac3285468 refactor(adminui): replace authorization string literals with AdminUiPolicies constants 2026-07-13 09:58:42 -04:00
Joseph Doherty dc2f3fa970 test(r2-06): pin 0.2.0 Boolean->Int1 explicit-presence (HasDataType) provisioning (06/U-7) 2026-07-13 09:58:07 -04:00
Joseph Doherty 6e1903b231 docs(r2-12): document 5 alarm operator CLI commands; fix StyleGuide product name; add minimal .editorconfig (07/U-3, 07/C-5)
- docs/Client.CLI.md: added ### ack / confirm / shelve / enable / disable sections
  (synopsis + options + example + expected output), each noting the AlarmAck LDAP-role
  gate and that --event-id comes from a prior `alarms` notification. Doc now covers all
  13 CLI commands (was 8). Overview operations list updated.
- StyleGuide.md: 'ScadaBridge' -> 'OtOpcUa' (header line 3) + the ScadaBridge:Timeout
  config-key example -> OpcUa:Timeout.
- .editorconfig (new, root): minimal code-style anchor; all C# analyzer rules at
  suggestion severity so nothing fails a TreatWarningsAsErrors build (verified: 808
  warnings unchanged from baseline, 0 errors).
2026-07-13 09:57:36 -04:00
Joseph Doherty b77bbd13b7 fix(r2-06): warning parity — malformed-endpoint warning in ServerHistorianOptions.Validate() (06/S-11) 2026-07-13 09:57:29 -04:00
Joseph Doherty b5bf4b73ff fix(adminui): gate every page with named policies — ConfigEditor on the mutating surface (R2-05, 04/C-1) 2026-07-13 09:56:08 -04:00
Joseph Doherty e748f929c8 fix(r2-06): wire AddValidatedOptions<ServerHistorianOptions> + alarm-only-mode startup warning in Program.cs (06/S-11) 2026-07-13 09:55:25 -04:00
Joseph Doherty 5369994e57 fix(r2-06): GREEN — ServerHistorianOptionsValidator (consumer-gated fail-fast on bad Endpoint) (06/S-11) 2026-07-13 09:54:37 -04:00
Joseph Doherty 67de2c942b ci(r2-12): delete no-op nightly E2E workflow + redundant integration matrix (07/S-3, 07/P-5)
- v2-e2e.yml deleted: its `--filter Category=E2E` matches zero tests repo-wide (the
  E2ETests project doesn't exist) so it reported a permanent false green; and its
  docker-dev fleet binds the LAN-only shared GLAuth (10.100.0.35:3893) + builds local
  images, so it isn't hosted-runner-bootable anyway. FOLLOW-UP: when a runner-reachable
  fleet + a real tests/Server/...E2ETests land, add a fresh workflow WITH a zero-match
  guard (fail if Category=E2E matches nothing).
- v2-ci.yml integration matrix removed: fully redundant with the unit-tests leg, which
  already runs both Host.IntegrationTests + OpcUaServer.IntegrationTests under the
  identical filter, fixtureless, gated at MIN_EXECUTED=1. No coverage lost. The S-2
  option-#2 fixture-backed-leg follow-up is preserved as a NOTE comment in the workflow.
Header comments updated; YAML validates; jobs are now build -> unit-tests.
2026-07-13 09:54:22 -04:00
Joseph Doherty 35d8abee84 fix(r2-06): RED — ServerHistorianOptionsValidator unit + wiring tests (net-new type; does not compile) (06/S-11) 2026-07-13 09:53:21 -04:00
Joseph Doherty 73d4061b77 chore(r2-12): untrack/archive root planning files; honor pending.md's never-stage rule (07/U-4)
- pending.md, current.md: git rm --cached (untrack, keep on disk) + root-anchored
  .gitignore entries — making the files' own declared 'never stage' rule true.
- looseends.md: deleted (2026-05-18 snapshot; sole open item + all follow-ups
  target the retired Wonderware historian sidecar rig, moot since the gateway
  cutover; recoverable from history).
- stillpending.md -> docs/plans/2026-06-18-stillpending-backlog-audit.md (git mv;
  referenced by docs/Historian.md + memory index, preserved under dated-plan convention).
- HISTORIAN-GATEWAY-INTEGRATION-ISSUES.md -> docs/plans/2026-06-27-historian-gateway-integration-issues.md (git mv).
- docs/Historian.md §'Closed backlog §2 items' repointed at the archived path.
Historical docs/plans/* references to the bare stillpending.md filename are frozen
point-in-time records, left untouched per the documentation-audit convention.
2026-07-13 09:53:01 -04:00
Joseph Doherty 183b72b7cb feat(security): add ConfigEditor + AuthenticatedRead AdminUI policies behind AdminUiPolicies constants 2026-07-13 09:52:13 -04:00
Joseph Doherty 3108abc13b fix(r2-06): GREEN adapter guard — TryCreate + named InvalidOperationException on bad ServerHistorian:Endpoint (06/S-11) 2026-07-13 09:52:07 -04:00
Joseph Doherty 3a049a13a4 fix(r2-06): RED repro — misconfigured ServerHistorian:Endpoint should fail with a named error, not UriFormatException (06/S-11) 2026-07-13 09:51:31 -04:00
Joseph Doherty 0aebffe800 chore(r2-12): U-6 husk dirs already absent in worktree — no deletion needed (07/U-6)
The 5 Driver.Historian.Wonderware* husks are untracked bin/obj build artifacts
(0 tracked files; absent from slnx). A fresh worktree carries no untracked files,
so there is nothing to rm. Only tracked Wonderware residue is the intentional
retired doc stub + closed-review findings.md (kept). Deviation recorded in plan.
2026-07-13 09:50:21 -04:00
Joseph Doherty d6ae8bd03a chore(r2-12): remove 7 orphaned proprietary AVEVA DLLs from lib/ (07/U-5)
Zero-reference proof passed: no *.csproj/*.props/*.targets/*.slnx names any
of the 7 binaries; no <HintPath> element exists repo-wide. Build clean after
removal. Added lib/ to .gitignore to block re-introduction.

Out of scope: purging these from git *history* (BFG/filter-repo) is a separate,
heavier decision that rewrites every clone; this removes them from the tip only.
2026-07-13 09:49:21 -04:00
Joseph Doherty 1676c8f40f Merge branch 'docs/archreview-r2-rereview-and-plans'
v2-ci / build (push) Successful in 3m10s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Failing after 4m16s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Failing after 1m46s
v2-ci / unit-tests (push) Failing after 8m29s
2026-07-12 23:52:32 -04:00
Joseph Doherty 1891f5d6a7 docs(archreview): 2026-07-12 re-review at f6eaa267 + 12 round-2 remediation plans
Re-ran all seven domain reviews at master f6eaa267 (reports rewritten in
place, each with a prior-finding status table): all 4 round-1 Criticals
verified closed; new top findings are the S7 connect-timeout OCE regression
(05/STAB-14), the ResilienceConfig operator-authorable brick (01/S-6), and
a batch of resilience-seam Mediums. 00-OVERALL.md carries the updated
maturity matrix + 12-item action list.

Adds R2-01..R2-12 design/implementation plans (one per action item, house
format + bite-sized TDD task breakdowns + co-located .tasks.json; 193 tasks,
~18-24 dev-days). STATUS.md updated: round-1 topology marked historical
(all merged+pushed), re-review findings table + plan pointers added.
2026-07-12 23:52:23 -04:00
Joseph Doherty f6eaa267a0 chore(deps): bump ZB.MOM.WW.HistorianGateway Client + Contracts 0.1.0 -> 0.2.0
v2-ci / build (push) Successful in 3m21s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Failing after 4m11s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Failing after 1m43s
v2-ci / unit-tests (push) Failing after 9m18s
Consume the published 0.2.0 gateway packages. M3 opc_quality gate checked
and CLEAR: OtOpcUa never writes HistorianHistoricalValue (uses only the
WriteLiveValues path, no opc_quality field), and every OpcQuality=0 is on
the read-side HistorianSample in test fixtures — unaffected by 0.2.0's
HistorianHistoricalValue.opc_quality proto3-optional change. Build clean;
gateway-driver 99/0 and runtime 364/0 tests pass.
2026-07-10 07:50:55 -04:00
Joseph Doherty 3b5ef439d4 docs(xmldoc): fix genuine doc issues surfaced by /fixdocs (17 fixes)
v2-ci / build (push) Successful in 3m11s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Failing after 3m51s
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Failing after 1m50s
v2-ci / unit-tests (push) Failing after 8m37s
- CapabilityInvoker: 3 methods that implement IDriverCapabilityInvoker now use
  <inheritdoc /> instead of duplicating the interface docs (MissingInheritDoc).
- TwinCAT NativeRegistration ctor: added the 8 missing <param> tags (MissingParam).
- Stripped the arch-review bookkeeping IDs STAB-1 (IS7Plc, S7Driver) + STAB-2
  (TwinCATDriver x4) from comments, keeping the descriptive text.

Left the other 86 flagged items untouched — they are checker false positives on
legitimate technical content: interface-implemented events / IEqualityComparer /
IDisposable members whose <inheritdoc/> IS correct (10 InheritDocMisused), and domain
terms the heuristic misreads as tracking IDs (IEEE-754, S7-1200/300/400/1500, PLC-5,
D2-260, S7/Melsec memory addresses, OPC UA Part 9, phase-N design-doc filename refs,
UNS level-N descriptions, and prose like 'the #1 bug source' / failover 'pick #3').
2026-07-10 06:23:12 -04:00
Joseph Doherty b67bd9e8b5 Merge branch 'docs/archreview-plans-and-drift-fixes'
v2-ci / build (push) Failing after 45s
v2-ci / unit-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-07-09 06:07:34 -04:00
Joseph Doherty 896eef0591 Merge branch 'fix/docker-dev-serverhistorian-stale-keys' 2026-07-09 06:07:34 -04:00
Joseph Doherty 83fdf5fa6c Merge branch 'fix/archreview-s1-s2-ci-coverage' 2026-07-09 06:07:33 -04:00
Joseph Doherty 1d7e7caa41 Merge branch 'fix/archreview-u2-deferred-sink-forwarding-guard' 2026-07-09 06:07:33 -04:00
Joseph Doherty 8f7b0017ef Merge branch 'fix/archreview-crit4-twincat-replay' 2026-07-09 06:07:33 -04:00
Joseph Doherty dfc02af3f0 Merge branch 'fix/archreview-crit3-s7-reconnect' 2026-07-09 06:07:33 -04:00
Joseph Doherty 45455b7677 Merge branch 'fix/archreview-crit2-vt-timeout' 2026-07-09 06:07:33 -04:00
Joseph Doherty 0ed30483b4 Merge branch 'fix/archreview-crit1-split-brain-resolver' 2026-07-09 06:07:33 -04:00
Joseph Doherty 025aac4d58 Merge branch 'fix/archreview-crit13-resilience-config-artifact' 2026-07-09 06:07:33 -04:00
Joseph Doherty dfeb21902d Merge branch 'fix/archreview-crit10-wire-capability-invoker' 2026-07-09 06:07:33 -04:00
Joseph Doherty 7834b3b71f Merge branch 'fix/archreview-c1-wire-analyzer' 2026-07-09 06:07:33 -04:00
Joseph Doherty 357709bc71 docs(archreview): docker-dev ServerHistorian rig bug FIXED (branch fix/docker-dev-serverhistorian-stale-keys 7233e2ba)
Flip the #12 rig-bug note from 'recommend fixing' to fixed: FOLLOWUP-10 + STATUS task #12
+ new branch topology row. central-1 verified booting clean with the committed compose.
2026-07-08 23:43:56 -04:00
Joseph Doherty 7233e2ba08 fix(docker-dev): replace retired Wonderware ServerHistorian keys with the gateway shape (disabled by default)
The historian-gateway cutover made ServerHistorianOptions read Endpoint/ApiKey/UseTls,
but docker-dev compose still set Enabled=true with the retired Wonderware Host/Port/
SharedSecret keys → HistorianGatewayClientAdapter.Create built a Uri from an empty
Endpoint → unhandled UriFormatException crashed the Host at every bring-up, leaving
docker-dev unbootable against current code.

central-1 + central-2 now use the gateway-shape keys, DISABLED by default (the rig has no
historian gateway): Enabled=${OTOPCUA_HISTORIAN_ENABLED:-false}, Endpoint/ApiKey via env,
UseTls + AllowUntrustedServerCertificate. To enable, set OTOPCUA_HISTORIAN_ENABLED=true +
OTOPCUA_HISTORIAN_ENDPOINT + export ServerHistorian__ApiKey (never committed). Verified:
compose config valid, central-1 boots clean (no UriFormatException; OPC UA + AdminUI serving).

Found during the arch-review #10 live-gate rig session; branched off master (independent
of the archreview work).
2026-07-08 23:43:02 -04:00
Joseph Doherty 347446d627 docs(archreview #12): record live-gate outcome (DI wiring confirmed live; behavioral log a disciplined stop)
Ran the #10 live gate: built the Host image from source (crit13 tip; Gitea feed answers
200 anonymously so restore worked), stood up the docker-dev rig, central-1 booted healthy
on the new invoker wiring. Prod DI binds the REAL DriverCapabilityInvokerFactory —
confirmed live + by a new deterministic guard (ResilienceInvokerFactoryRegistrationTests,
crit13 8a8b9ec5). The behavioral retry/breaker log-line was NOT observed: reading the
Modbus driver showed its cheap paths don't throw a wrapped exception (Discover offline,
Subscribe lazy, reads non-wrapped) — only an idempotent write-to-dead-endpoint or S7 does,
not worth the multi-dependency chase since the retry behavior is deterministically proven.

Also found a rig bug: docker-dev compose's retired Wonderware ServerHistorian keys
(Host/Port/SharedSecret, Enabled=true) crash the Host at bring-up (historian-gateway cutover
now reads Endpoint -> empty UriFormatException). Worked around with an override; recommend
fixing the committed compose. FOLLOWUP-10 + STATUS updated; crit13 topology head -> 8a8b9ec5.
2026-07-08 23:25:31 -04:00
Joseph Doherty 8a8b9ec564 test(archreview #10/#13): guard prod DI binds the REAL invoker factory
AddOtOpcUaDriverFactories (the driver-node bootstrap) must bind the real
DriverCapabilityInvokerFactory — not the NullDriverCapabilityInvokerFactory
pass-through — and it must mint a real CapabilityInvoker per instance. This is the
deterministic DI half of the #10 live gate: a refactor dropping back to the
pass-through would make the whole retry/breaker/bulkhead pipeline inert in production
while every pass-through-defaulting unit test stays green. 3 tests (real factory bound,
real invoker minted, shared singletons), non-fixtured. Host.IntegrationTests.
2026-07-08 23:16:23 -04:00
Joseph Doherty 051a59845d docs(archreview): record #13 IMPLEMENTED (ResilienceConfig read-path plumbing)
- New FOLLOWUP-13: the DriverInstance.ResilienceConfig column was authored/persisted
  and already in the artifact; only the driver-node read path dropped it. Read-path
  plumbing + invalidate-on-change + respawn-on-change; deterministic verification.
- FOLLOWUP-10 sub-gap (a) 'tier-defaults only' → RESOLVED by #13 (sub-gap (b) tracker
  reader still open).
- STATUS.md: task #13 → completed; crit13 branch topology row; Completed-table row;
  findings #10 bullet updated; FOLLOWUP-13 linked.
2026-07-08 22:51:15 -04:00
Joseph Doherty 75403caa1a feat(archreview #13): apply per-instance ResilienceConfig from the deploy artifact
The DriverInstance.ResilienceConfig column was authored in AdminUI, persisted to the
entity, and serialized into the deployment artifact by ConfigComposer — but the runtime
read path dropped it: DriverInstanceSpec didn't carry it and the invoker factory always
passed null, so every driver got tier defaults regardless of its configured overrides
(a silent dead-config gap — #10's residual sub-finding).

Read-path plumbing (write side was already complete):
- DriverInstanceSpec gains ResilienceConfig; DeploymentArtifact.TryReadSpec reads the column.
- IDriverCapabilityInvokerFactory.Create takes resilienceConfigJson; DriverHostActor.SpawnChild
  threads spec.ResilienceConfig; the concrete factory parses it (ParseOrDefaults, layering on the
  tier), logs any parse diagnostic (never throws), and builds the invoker with the merged options.
- Invalidate-on-change: the pipeline cache keys on (instance, host, capability) and ignores options
  on a hit, so Create() now Invalidate()s the instance's cached pipelines first (no-op on first
  spawn) — a respawn with changed options rebuilds them.
- DriverSpawnPlanner treats a ResilienceConfig change as a stop+respawn (the invoker/options are
  bound to the child at spawn); a pure DriverConfig change stays an in-place delta (no reconnect).
- Host DI passes a logger to the factory for the parse diagnostic.

Verification (deterministic): factory Create applies a retryCount:0 override to actual execution
(control test proves tier default retries), invalidates the instance's cache on re-create (scoped —
sibling survives), malformed config logs+falls-back; planner respawns on ResilienceConfig change
(incl null→json) and stays delta on a pure config change; artifact parse carries/omits the column.
Core.Tests 243 (+5), Runtime.Tests 363 (+5), Host builds clean.
2026-07-08 22:48:17 -04:00
Joseph Doherty e233db7456 docs(archreview): record #11 CORRECTED (Crit-1 premise) + track residual #12/#13
- FOLLOWUP-11 → IMPLEMENTED with outcome (docs/comment-only, no code revert; the four
  corrected sites; Cluster.Tests 29/29).
- STATUS.md: task #11 → completed; crit1 branch head → eaf78aad; Completed-table row;
  Findings #11 bullet flipped to CORRECTED; added task rows #12 (live gate) + #13
  (ResilienceConfig-in-artifact).
2026-07-08 22:36:10 -04:00