Files
scadaproj/components
Joseph Doherty 5198d3dc7f docs(secrets): close out scadaproj#3 — gRPC hub shipped 0.4.1, both live gates PASS; residual filed as #4
Task 9 (closeout) of the Secrets gRPC-hub program. Bookkeeping only; no code.

- clustered-secrets.md, Production enablement: the gRPC hub is no longer
  pending. It is BUILT, SHIPPED (0.4.1) and LIVE-GATED PASS 4/4 (ScadaBridge
  main @ f6c3f7c5, docs/plans/2026-08-07-secrets-grpc-hub-live-gate.md), so the
  "until that ships, ScadaBridge replication stays off" line is replaced with
  the truth: the code path is merged and gated, and production enablement is a
  separate operator action behind a still-default-off flag. OtOpcUa's
  pair-local topology is recorded as live-gated (lmxopcua master @ 1bd79c8e)
  rather than pending re-gate. Rotation fan-out corrected: on ScadaBridge it is
  BOTH central nodes plus both nodes of every site pair, because each central
  node has its own independent store.

- components/secrets/GAPS.md: new "gRPC hub delivered" section recording the
  0.4.0/0.4.1 publish, both gates with SHAs and gate-doc paths, and the
  residual. Existing narrative left intact and amended, not rewritten.

- CLAUDE.md Secrets row: lib version 0.3.0 -> 0.4.1 and the app-pin claim
  corrected (ScadaBridge pins 0.4.1 for the Grpc replicator; the other three
  still pin 0.2.3); the "production topologies DECIDED" region now records
  delivery, both gates, default-off, and the residual.

- Plan ledger: task 9 completed.

Residual carried forward as scadaproj#4 — ScadaBridge's central pair does not
converge with itself (central-b served an authenticated but EMPTY manifest all
gate while central-a held every secret) and the site client dials a single
endpoint; these are one design question, since failover to an empty hub would
succeed and silently stop convergence. scadaproj#3 is closed.

Claude-Session: https://claude.ai/code/session_014WNM4vjoVksyyBraTXSZE1
2026-08-07 09:00:11 -04:00
..

Component normalization

This tree normalizes how cross-cutting components work across the sister projects indexed in ../CLAUDE.md (currently OtOpcUa, MxAccessGateway, ScadaBridge). The sister repos are deliberately decoupled — separate processes coupled only over wire protocols — so the same concern (auth, logging, config, health, …) tends to get re-implemented three times and drift apart. This folder is where we write down the one target for each such component, record where each project stands today (verified against real code), and track the gaps that close the distance between them.

The goal is convergence toward shared, versioned contracts/libraries — see each component's shared-contract/. Nothing here changes project code directly; these are specs and analyses that drive changes made in the individual repos.

Component registry

Component Status Applies to Goal Folder
Auth (login / identity / authz) Adopted OtOpcUa, MxAccessGateway, ScadaBridge Path to shared code (ZB.MOM.WW.Auth) auth/
UI Theme (layout / tokens / components) Adopted OtOpcUa, MxAccessGateway, ScadaBridge Path to shared code (ZB.MOM.WW.Theme) ui-theme/
Health (readiness / liveness / active-node) Adopted OtOpcUa, MxAccessGateway, ScadaBridge Shared ZB.MOM.WW.Health lib (3 packages) health/
Observability (metrics / traces / logs) Adopted OtOpcUa, MxAccessGateway, ScadaBridge Shared ZB.MOM.WW.Telemetry lib (2 packages) observability/
Config + validation (options / startup validation) Adopted OtOpcUa, MxAccessGateway, ScadaBridge Shared ZB.MOM.WW.Configuration lib (1 package) configuration/
Audit (event model + writer seam) Adopted OtOpcUa, MxAccessGateway, ScadaBridge Path to shared code (ZB.MOM.WW.Audit) audit/
Secrets (encrypted store + ${secret:} resolution) Adopted (all four apps pin 0.2.3) OtOpcUa, MxAccessGateway, ScadaBridge Shared ZB.MOM.WW.Secrets lib (5 packages + CLI) secrets/

Add a row when you start normalizing a new component. Status: Draft → Reviewed → Adopting → Converged.

Folder convention

Every normalized component is one subfolder of components/ with this layout:

<component>/
  README.md                     # overview + per-project status table (links into the docs below)
  spec/
    SPEC.md                     # the ONE normalized target for this component
  shared-contract/              # only when the goal is shared code
    <Package>.md                # proposed shared-library API: packages, interfaces, options, records
  current-state/
    <project>/                  # one subfolder per project the component applies to
      CURRENT-STATE.md          # how it works in THAT project today (code-verified) + adoption plan
  GAPS.md                       # divergences of each project vs SPEC.md + the extraction/adoption backlog
  • spec/SPEC.md is authoritative: the single design every project should converge on.
  • shared-contract/ exists only when the component's goal is shared code (vs docs-only convergence). It is the proposed public API of the library to extract — a contract on paper, not a created package.
  • current-state/<project>/ is descriptive, not aspirational. It must match the project's real code, with file:line references. Each ends in an Adoption plan: what that project deletes/replaces to reach the spec, and what stays bespoke.
  • GAPS.md is the working backlog: it turns the delta between every current-state and the spec into concrete, prioritized items.

Workflow to normalize a component

  1. Map current state from code. For each applicable project, read the actual implementation (not just its CLAUDE.md) and write current-state/<project>/CURRENT-STATE.md with file:line refs. Fan out one reader per project — they're independent.
  2. Write the target. Synthesize the common ground and the divergences into spec/SPEC.md — the one design. Call out explicitly what is normalized vs. what stays per-project (domain differences that should not be forced together).
  3. Propose the contract (if shared-code goal). Turn the spec's normalized seams into a concrete library API in shared-contract/. Keep the surface minimal — extract only what is genuinely common; leave domain-specific logic in the projects.
  4. Log gaps + adoption. Fill GAPS.md with per-project divergences and an adoption/extraction backlog (priority / effort / risk). Add the per-project "what to delete/replace" to each current-state doc.
  5. Register. Add/maintain the component's row in the registry table above.

Maintenance rules

  • current-state/<project>/CURRENT-STATE.md must stay code-verified. When a project's auth (or whichever component) changes materially, update its current-state doc and re-check GAPS.md.
  • The spec/ is changed deliberately, with the same "update the doc and the consequences" discipline the sister repos use — moving the target re-opens gaps.
  • Keep cross-references accurate: README.md status tables link to the docs; don't let them rot.