# Component normalization This tree normalizes how cross-cutting components work across the sister projects indexed in [`../CLAUDE.md`](../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) | Draft | OtOpcUa, MxAccessGateway, ScadaBridge | Path to shared code (`ZB.MOM.WW.Auth`) | [`auth/`](auth/) | | UI Theme (layout / tokens / components) | Draft | OtOpcUa, MxAccessGateway, ScadaBridge | Path to shared code (`ZB.MOM.WW.Theme`) | [`ui-theme/`](ui-theme/) | | Health (readiness / liveness / active-node) | Draft | OtOpcUa, MxAccessGateway, ScadaBridge | Shared `ZB.MOM.WW.Health` lib (3 packages) | [`health/`](health/) | | Observability (metrics / traces / logs) | Draft | OtOpcUa, MxAccessGateway, ScadaBridge | Shared `ZB.MOM.WW.Telemetry` lib (2 packages) | [`observability/`](observability/) | | Config + validation (options / startup validation) | Draft | OtOpcUa, MxAccessGateway, ScadaBridge | Shared `ZB.MOM.WW.Configuration` lib (1 package) | [`configuration/`](configuration/) | | Audit (event model + writer seam) | Draft | OtOpcUa, MxAccessGateway, ScadaBridge | Path to shared code (`ZB.MOM.WW.Audit`) | [`audit/`](audit/) | > 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: ``` / 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 .md # proposed shared-library API: packages, interfaces, options, records current-state/ / # 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//`** 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//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//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.