# 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/) |
| Secrets (encrypted store + `${secret:}` resolution) | Built + reference-consumer adopted | OtOpcUa, MxAccessGateway, ScadaBridge | Shared `ZB.MOM.WW.Secrets` lib (3 packages + CLI) | [`secrets/`](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.
