Add per-library code-review scaffolding for the ZB.MOM.WW.* shared libs

Adapts the code-reviews convention (process, README generator, template) from
the ScadaBridge app model (per-src/-module, Akka conventions) to scadaproj's
reality: six shared libraries reviewed against their components/ specs.

- REVIEW-PROCESS.md: review unit is a library; library->component-spec mapping;
  checklist re-targeted for reusable .NET libs (public API/semver, packaging &
  dependency hygiene, spec/shared-contract adherence) instead of actor/supervision.
- _template/findings.md: library/packages/component-spec/shared-contract header.
- regen-readme.py: per-library prose, data-driven Summary, '-' for unreviewed.
- Seed Auth/Theme/Health/Telemetry/Configuration/Audit findings stubs (0 findings).
- README.md generated; --check passes.
This commit is contained in:
Joseph Doherty
2026-06-01 10:46:16 -04:00
parent 899efc2cbf
commit 5f75cd4dab
10 changed files with 717 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
# Code Review — Audit
| Field | Value |
|-------|-------|
| Library | `ZB.MOM.WW.Audit/` |
| Packages | `ZB.MOM.WW.Audit` |
| Component spec | `components/audit/spec/SPEC.md` |
| Shared contract | `components/audit/shared-contract/ZB.MOM.WW.Audit.md` |
| Status | Not yet reviewed |
| Last reviewed | — |
| Reviewer | — |
| Commit reviewed | — |
| Open findings | 0 |
## Summary
_Not yet reviewed._
## Checklist coverage
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☐ | |
| 2 | Public API surface & compatibility | ☐ | |
| 3 | Concurrency & thread safety | ☐ | |
| 4 | Error handling & resilience | ☐ | |
| 5 | Security & secret handling | ☐ | |
| 6 | Performance & resource management | ☐ | |
| 7 | Spec & shared-contract adherence | ☐ | |
| 8 | Packaging, dependencies & project layout | ☐ | |
| 9 | Testing coverage | ☐ | |
| 10 | Documentation & XML docs | ☐ | |
## Findings
_No findings recorded yet._
+36
View File
@@ -0,0 +1,36 @@
# Code Review — Auth
| Field | Value |
|-------|-------|
| Library | `ZB.MOM.WW.Auth/` |
| Packages | `ZB.MOM.WW.Auth.Abstractions`, `ZB.MOM.WW.Auth.Ldap`, `ZB.MOM.WW.Auth.ApiKeys`, `ZB.MOM.WW.Auth.AspNetCore` |
| Component spec | `components/auth/spec/SPEC.md` |
| Shared contract | `components/auth/shared-contract/ZB.MOM.WW.Auth.md` |
| Status | Not yet reviewed |
| Last reviewed | — |
| Reviewer | — |
| Commit reviewed | — |
| Open findings | 0 |
## Summary
_Not yet reviewed._
## Checklist coverage
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☐ | |
| 2 | Public API surface & compatibility | ☐ | |
| 3 | Concurrency & thread safety | ☐ | |
| 4 | Error handling & resilience | ☐ | |
| 5 | Security & secret handling | ☐ | |
| 6 | Performance & resource management | ☐ | |
| 7 | Spec & shared-contract adherence | ☐ | |
| 8 | Packaging, dependencies & project layout | ☐ | |
| 9 | Testing coverage | ☐ | |
| 10 | Documentation & XML docs | ☐ | |
## Findings
_No findings recorded yet._
+36
View File
@@ -0,0 +1,36 @@
# Code Review — Configuration
| Field | Value |
|-------|-------|
| Library | `ZB.MOM.WW.Configuration/` |
| Packages | `ZB.MOM.WW.Configuration` |
| Component spec | `components/configuration/spec/SPEC.md` |
| Shared contract | `components/configuration/shared-contract/ZB.MOM.WW.Configuration.md` |
| Status | Not yet reviewed |
| Last reviewed | — |
| Reviewer | — |
| Commit reviewed | — |
| Open findings | 0 |
## Summary
_Not yet reviewed._
## Checklist coverage
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☐ | |
| 2 | Public API surface & compatibility | ☐ | |
| 3 | Concurrency & thread safety | ☐ | |
| 4 | Error handling & resilience | ☐ | |
| 5 | Security & secret handling | ☐ | |
| 6 | Performance & resource management | ☐ | |
| 7 | Spec & shared-contract adherence | ☐ | |
| 8 | Packaging, dependencies & project layout | ☐ | |
| 9 | Testing coverage | ☐ | |
| 10 | Documentation & XML docs | ☐ | |
## Findings
_No findings recorded yet._
+36
View File
@@ -0,0 +1,36 @@
# Code Review — Health
| Field | Value |
|-------|-------|
| Library | `ZB.MOM.WW.Health/` |
| Packages | `ZB.MOM.WW.Health`, `ZB.MOM.WW.Health.Akka`, `ZB.MOM.WW.Health.EntityFrameworkCore` |
| Component spec | `components/health/spec/SPEC.md` |
| Shared contract | `components/health/shared-contract/ZB.MOM.WW.Health.md` |
| Status | Not yet reviewed |
| Last reviewed | — |
| Reviewer | — |
| Commit reviewed | — |
| Open findings | 0 |
## Summary
_Not yet reviewed._
## Checklist coverage
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☐ | |
| 2 | Public API surface & compatibility | ☐ | |
| 3 | Concurrency & thread safety | ☐ | |
| 4 | Error handling & resilience | ☐ | |
| 5 | Security & secret handling | ☐ | |
| 6 | Performance & resource management | ☐ | |
| 7 | Spec & shared-contract adherence | ☐ | |
| 8 | Packaging, dependencies & project layout | ☐ | |
| 9 | Testing coverage | ☐ | |
| 10 | Documentation & XML docs | ☐ | |
## Findings
_No findings recorded yet._
+80
View File
@@ -0,0 +1,80 @@
# Code Reviews
Comprehensive, per-library code reviews of the `ZB.MOM.WW.*` shared libraries hosted
in this repo. Each library (one self-contained `.slnx` at the repo root) has its own
folder containing a `findings.md`. This README is the aggregated index — the single
place to see all outstanding work.
> Generated by `regen-readme.py` from the per-library `findings.md` files. Do not
> edit by hand — edit the findings files and re-run the script.
## How it works
- Reviews are performed one library at a time against a fixed checklist.
- Each library is reviewed against its normalized component spec under `components/`.
- Every finding is recorded in the library's `findings.md` with a severity and status.
- Findings are **never deleted** — they are closed by changing their status, keeping
a full audit trail.
- This README aggregates every **pending** finding (`Open` / `In Progress`) across all
libraries.
See **[REVIEW-PROCESS.md](REVIEW-PROCESS.md)** for the full procedure: the review
checklist, severity definitions, finding format, the library → component-spec mapping,
and how to mark items resolved.
## Layout
```
code-reviews/
├── README.md # this file — process overview + pending findings
├── REVIEW-PROCESS.md # how to perform a review and track findings
├── regen-readme.py # regenerates this README from the findings files
├── _template/findings.md # copy-this template for a library review
└── <Library>/findings.md # one folder per ZB.MOM.WW.* shared library
```
## Summary
0 of 6 libraries reviewed. 0 pending findings across all libraries.
| Severity | Open findings |
|----------|---------------|
| Critical | 0 |
| High | 0 |
| Medium | 0 |
| Low | 0 |
| **Total** | **0** |
## Library Status
| Library | Last reviewed | Commit | Open (C/H/M/L) | Open | Total |
|---------|---------------|--------|----------------|------|-------|
| [Audit](Audit/findings.md) | — | — | 0/0/0/0 | 0 | 0 |
| [Auth](Auth/findings.md) | — | — | 0/0/0/0 | 0 | 0 |
| [Configuration](Configuration/findings.md) | — | — | 0/0/0/0 | 0 | 0 |
| [Health](Health/findings.md) | — | — | 0/0/0/0 | 0 | 0 |
| [Telemetry](Telemetry/findings.md) | — | — | 0/0/0/0 | 0 | 0 |
| [Theme](Theme/findings.md) | — | — | 0/0/0/0 | 0 | 0 |
## Pending Findings
Every `Open` / `In Progress` finding across all libraries, highest severity first.
Resolved findings drop off this list but remain recorded in their library's
`findings.md` (see [REVIEW-PROCESS.md](REVIEW-PROCESS.md) §4–§5). Full detail —
description, location, recommendation — lives in the library's `findings.md`.
### Critical (0)
_None open._
### High (0)
_None open._
### Medium (0)
_None open._
### Low (0)
_None open._
+152
View File
@@ -0,0 +1,152 @@
# Code Review Process
This document describes how to perform a comprehensive, per-library code review of the
shared libraries hosted in **scadaproj** and how to track findings to resolution.
scadaproj is an umbrella workspace, but it hosts first-party source: the six
`ZB.MOM.WW.*` shared libraries (the realized output of the
[component normalizations](../components/README.md)). Those libraries are the code that
gets reviewed here. A **library** is one self-contained solution at the repo root (its own
`.slnx`, with `src/` and `tests/`) — e.g. `ZB.MOM.WW.Auth/`. Each library has its own
folder under `code-reviews/` containing a single `findings.md`.
The review unit is the **library**, not the individual NuGet package. A library that ships
several packages (Auth → 4, Health → 3, Telemetry → 2) is reviewed as a whole; findings
point at the specific package/file in their **Location**.
### The six libraries and their design context
Each library is reviewed against its normalized component spec. The library folder name is
the `ZB.MOM.WW.` prefix stripped; note the spec directory is **not** always the same word.
| Library folder | Library root | Packages | Component spec |
|----------------|--------------|----------|----------------|
| `Auth` | `ZB.MOM.WW.Auth/` | `Abstractions`, `Ldap`, `ApiKeys`, `AspNetCore` | [`components/auth/`](../components/auth/) |
| `Theme` | `ZB.MOM.WW.Theme/` | single RCL | [`components/ui-theme/`](../components/ui-theme/) |
| `Health` | `ZB.MOM.WW.Health/` | `Health`, `.Akka`, `.EntityFrameworkCore` | [`components/health/`](../components/health/) |
| `Telemetry` | `ZB.MOM.WW.Telemetry/` | `Telemetry`, `.Serilog` | [`components/observability/`](../components/observability/) |
| `Configuration` | `ZB.MOM.WW.Configuration/` | single | [`components/configuration/`](../components/configuration/) |
| `Audit` | `ZB.MOM.WW.Audit/` | single | [`components/audit/`](../components/audit/) |
## 1. Before you start
1. Pick the library to review. Its review folder is `code-reviews/<Library>/` where
`<Library>` is the table above (the `ZB.MOM.WW.` prefix stripped).
2. Identify the design context for the library:
- Its component spec: `components/<component>/spec/SPEC.md`.
- Its proposed shared contract: `components/<component>/shared-contract/ZB.MOM.WW.<Library>.md`.
- The library's own `README.md` and the relevant row in the **Component normalization**
table in the root [`CLAUDE.md`](../CLAUDE.md).
- The adoption backlog `components/<component>/GAPS.md` (what is deliberately deferred).
3. Record the exact commit being reviewed: `git rev-parse --short HEAD`. Every review is a
snapshot — a finding only means something relative to a known commit.
4. Build and test the library so findings are grounded in a green (or known-red) baseline:
`cd ZB.MOM.WW.<Library> && dotnet test`.
5. Open `code-reviews/<Library>/findings.md` and fill in the header table (reviewer, date,
commit SHA).
## 2. Review checklist
Work through **every** category below for the library. A comprehensive review means the
checklist is completed even where it produces no findings — record "No issues found" for a
category rather than leaving it ambiguous.
These libraries are reusable packages consumed by three separate apps (OtOpcUa,
MxAccessGateway, ScadaBridge), so the bar is **API stability and minimal blast radius**:
a defect here can break every consumer at once.
1. **Correctness & logic bugs** — off-by-one, null handling, incorrect conditionals,
misuse of BCL/framework APIs, broken edge cases.
2. **Public API surface & compatibility** — the public surface is intentional and minimal;
naming follows .NET conventions; nullable reference annotations are correct; `sealed` /
`abstract` / `virtual` choices are deliberate; no internal types leak through public
signatures; evolution is additive-only with semver discipline (libraries are at `0.1.0`).
3. **Concurrency & thread safety** — these libraries run inside concurrent hosts; options
and value types are immutable, singletons/statics are thread-safe, no shared mutable
state, correct `async`/`await`, no sync-over-async.
4. **Error handling & resilience** — exceptions thrown to consumers are appropriate and
documented; argument validation / guard clauses (`ArgumentNullException` etc.); no
swallowed exceptions; fail-fast vs. graceful degradation is deliberate.
5. **Security & secret handling** — Auth peppered-HMAC API keys and LDAP-injection surface;
redaction seams (`ILogRedactor` in Telemetry, `IAuditRedactor` in Audit); input
validation; no secrets or PII in messages, logs, or exception text.
6. **Performance & resource management**`IDisposable` correctness and disposal,
allocations on hot paths, buffering/back-pressure, no unnecessary work in DI
registration, async all the way down.
7. **Spec & shared-contract adherence** — does the code match the library's
`components/<component>/spec/SPEC.md` and `shared-contract/ZB.MOM.WW.<Library>.md`?
Flag both code that drifts from the normalized contract **and** spec/contract docs that
are now stale relative to the code.
8. **Packaging, dependencies & project layout** — minimal dependency footprint (e.g. Audit's
only non-BCL dependency is `Microsoft.Extensions.DependencyInjection.Abstractions`);
correct target framework (.NET 10); package id/version metadata; `dotnet pack` produces
the expected nupkg set; central versions in `Directory.Packages.props`; no public
dependency leakage; Abstractions-vs-implementation split; Options pattern owned by the
library; `AddZb*` DI registration ergonomics.
9. **Testing coverage** — are the library's behaviours covered by tests in its `tests/`
project? Note untested critical paths, missing edge-case tests, and whether the public
contract (not just internals) is exercised.
10. **Documentation & XML docs** — XML doc accuracy and presence on the **public** API
(these are libraries — public docs matter), library `README.md` correctness, misleading
or stale comments, undocumented non-obvious behaviour.
## 3. Recording findings
Add one entry per finding to the `## Findings` section of the library's `findings.md`,
using the entry format in [`_template/findings.md`](_template/findings.md).
- **Finding ID** — `<Library>-NNN`, numbered sequentially within the library and never
reused (e.g. `Auth-001`, `Telemetry-003`). IDs are permanent even after resolution.
- **Severity:**
- **Critical** — security breach, data loss, or a defect that crashes/corrupts or
deadlocks every consuming app (e.g. a broken public contract, secret leakage).
- **High** — incorrect behaviour with significant impact across consumers, or a
public-API / back-compat break, with no safe workaround.
- **Medium** — incorrect or risky behaviour with limited impact or a workaround.
- **Low** — minor issues, style, maintainability, documentation.
- **Category** — one of the 10 checklist categories above.
- **Location** — `file:line` (clickable), or a list of locations.
- **Description** — what is wrong and why it matters.
- **Recommendation** — concrete suggested fix.
After recording findings, update the library header table (status, open-finding count) and
refresh the base README (step 5).
## 4. Marking an item resolved
Findings are **never deleted** — they are an audit trail. To close one, change its
**Status** and complete the **Resolution** field:
- `Open` — newly recorded, not yet addressed.
- `In Progress` — a fix is actively being worked on.
- `Resolved` — fixed. The Resolution field must state the fixing commit SHA, the date, and
a one-line description of the fix.
- `Won't Fix` — intentionally not fixed. The Resolution field must justify why.
- `Deferred` — valid but postponed. The Resolution field must say what it is waiting on
(e.g. a tracked issue, a `GAPS.md` item, or a later milestone).
`Resolved`, `Won't Fix`, and `Deferred` findings are all considered **closed** and drop off
the base README's pending list. `Open` and `In Progress` are **pending**.
## 5. Updating the base README
`code-reviews/README.md` holds the single cross-library view (process overview, the Pending
Findings tables, and the Library Status table). It is **generated** from the per-library
`findings.md` files — do not edit it by hand.
After any review or status change, regenerate it:
```
python3 code-reviews/regen-readme.py
```
`regen-readme.py --check` exits non-zero if `README.md` is stale, for use in CI.
The per-library `findings.md` files are the source of truth; `README.md` is the aggregated
index and must always agree with them — which the script guarantees.
## 6. Re-reviewing a library
Re-reviews append to the same `findings.md`. Update the header to the new commit and date,
continue the finding numbering from the last used ID, and leave prior findings (including
closed ones) in place as history.
+36
View File
@@ -0,0 +1,36 @@
# Code Review — Telemetry
| Field | Value |
|-------|-------|
| Library | `ZB.MOM.WW.Telemetry/` |
| Packages | `ZB.MOM.WW.Telemetry`, `ZB.MOM.WW.Telemetry.Serilog` |
| Component spec | `components/observability/spec/SPEC.md` |
| Shared contract | `components/observability/shared-contract/ZB.MOM.WW.Telemetry.md` |
| Status | Not yet reviewed |
| Last reviewed | — |
| Reviewer | — |
| Commit reviewed | — |
| Open findings | 0 |
## Summary
_Not yet reviewed._
## Checklist coverage
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☐ | |
| 2 | Public API surface & compatibility | ☐ | |
| 3 | Concurrency & thread safety | ☐ | |
| 4 | Error handling & resilience | ☐ | |
| 5 | Security & secret handling | ☐ | |
| 6 | Performance & resource management | ☐ | |
| 7 | Spec & shared-contract adherence | ☐ | |
| 8 | Packaging, dependencies & project layout | ☐ | |
| 9 | Testing coverage | ☐ | |
| 10 | Documentation & XML docs | ☐ | |
## Findings
_No findings recorded yet._
+36
View File
@@ -0,0 +1,36 @@
# Code Review — Theme
| Field | Value |
|-------|-------|
| Library | `ZB.MOM.WW.Theme/` |
| Packages | `ZB.MOM.WW.Theme` (Razor Class Library) |
| Component spec | `components/ui-theme/spec/SPEC.md` |
| Shared contract | `components/ui-theme/shared-contract/ZB.MOM.WW.Theme.md` |
| Status | Not yet reviewed |
| Last reviewed | — |
| Reviewer | — |
| Commit reviewed | — |
| Open findings | 0 |
## Summary
_Not yet reviewed._
## Checklist coverage
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☐ | |
| 2 | Public API surface & compatibility | ☐ | |
| 3 | Concurrency & thread safety | ☐ | |
| 4 | Error handling & resilience | ☐ | |
| 5 | Security & secret handling | ☐ | |
| 6 | Performance & resource management | ☐ | |
| 7 | Spec & shared-contract adherence | ☐ | |
| 8 | Packaging, dependencies & project layout | ☐ | |
| 9 | Testing coverage | ☐ | |
| 10 | Documentation & XML docs | ☐ | |
## Findings
_No findings recorded yet._
+71
View File
@@ -0,0 +1,71 @@
# Code Review — <Library>
<!--
Template for a shared-library review. Copy the structure below into
code-reviews/<Library>/findings.md and fill it in.
<Library> is the ZB.MOM.WW.* library with the prefix stripped (Auth, Theme,
Health, Telemetry, Configuration, Audit). See ../REVIEW-PROCESS.md for the
full process and the library → component-spec mapping.
-->
| Field | Value |
|-------|-------|
| Library | `ZB.MOM.WW.<Library>/` |
| Packages | `<package ids, e.g. ZB.MOM.WW.<Library>>` |
| Component spec | `components/<component>/spec/SPEC.md` |
| Shared contract | `components/<component>/shared-contract/ZB.MOM.WW.<Library>.md` |
| Status | Not yet reviewed \| In progress \| Reviewed |
| Last reviewed | YYYY-MM-DD |
| Reviewer | <name> |
| Commit reviewed | `<short SHA>` |
| Open findings | 0 |
## Summary
One short paragraph: overall health of the library, themes across findings, and anything
notable that is not a finding (e.g. test count, dependency footprint, adoption status).
## Checklist coverage
Confirm every category was examined. Record "No issues found" where applicable.
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☐ | |
| 2 | Public API surface & compatibility | ☐ | |
| 3 | Concurrency & thread safety | ☐ | |
| 4 | Error handling & resilience | ☐ | |
| 5 | Security & secret handling | ☐ | |
| 6 | Performance & resource management | ☐ | |
| 7 | Spec & shared-contract adherence | ☐ | |
| 8 | Packaging, dependencies & project layout | ☐ | |
| 9 | Testing coverage | ☐ | |
| 10 | Documentation & XML docs | ☐ | |
## Findings
<!-- One entry per finding. Copy the block below. Never delete a finding; close it
by changing Status and completing Resolution. -->
### <Library>-001 — <Short title>
| | |
|--|--|
| Severity | Critical \| High \| Medium \| Low |
| Category | <one of the 10 checklist categories> |
| Status | Open \| In Progress \| Resolved \| Won't Fix \| Deferred |
| Location | `ZB.MOM.WW.<Library>/src/<Package>/<File>.cs:<line>` |
**Description**
What is wrong and why it matters.
**Recommendation**
Concrete suggested fix.
**Resolution**
_Unresolved._
<!-- When closed: fixing commit `<SHA>`, date YYYY-MM-DD, one-line description.
For Won't Fix / Deferred, justify the decision here. -->
+198
View File
@@ -0,0 +1,198 @@
#!/usr/bin/env python3
"""Regenerate code-reviews/README.md from the per-library findings.md files.
The findings files are the source of truth; README.md is a generated index.
Run this after recording, resolving, or re-triaging a finding so the aggregated
tables stay in sync (see REVIEW-PROCESS.md section 5).
Usage:
python3 regen-readme.py # rewrite README.md
python3 regen-readme.py --check # exit 1 if README.md is stale (for CI)
Works from any directory — paths are resolved relative to this script.
"""
import os
import re
import sys
BASE = os.path.dirname(os.path.abspath(__file__))
SEVERITY_ORDER = {"Critical": 0, "High": 1, "Medium": 2, "Low": 3}
PENDING_STATUSES = {"Open", "In Progress"}
NOT_REVIEWED = "" # rendered for libraries with no recorded review date/commit yet
def discover_libraries():
"""Library folders are every subdirectory of code-reviews/ holding a findings.md,
excluding the _template folder. Returned sorted for a stable README order."""
libraries = []
for name in sorted(os.listdir(BASE)):
if name.startswith(("_", ".")):
continue
if os.path.isfile(os.path.join(BASE, name, "findings.md")):
libraries.append(name)
return libraries
def parse_header(library, text):
"""Extract (last_reviewed, commit) from the library's header table.
Returns None for either field when it is absent or still templated, so the
README can render a 'not yet reviewed' dash instead of a fake baseline."""
last = re.search(r"\|\s*Last reviewed\s*\|\s*([0-9]{4}-[0-9]{2}-[0-9]{2})", text)
commit = re.search(r"\|\s*Commit reviewed\s*\|\s*`([^`<]+)`", text)
return (
last.group(1) if last else None,
commit.group(1) if commit else None,
)
def parse_findings(library):
"""Parse one library's findings.md into ((last_reviewed, commit), [(library, id, severity, title, status), ...])."""
text = open(os.path.join(BASE, library, "findings.md")).read()
header = parse_header(library, text)
findings = []
for block in re.split(r"^### ", text, flags=re.M)[1:]:
head = block.splitlines()[0].strip()
m = re.match(r"([A-Za-z][A-Za-z0-9]*-\d+)\b(.*)", head)
if not m:
raise SystemExit(f"{library}/findings.md: unparseable finding heading: {head!r}")
fid = m.group(1).strip()
title = m.group(2).strip().lstrip("—–-").strip().replace("|", "\\|")
sev = re.search(r"\|\s*Severity\s*\|\s*([A-Za-z]+)", block)
status = re.search(r"\|\s*Status\s*\|\s*([A-Za-z' ]+?)\s*\|", block)
if not sev or not status:
raise SystemExit(f"{library}/findings.md: {fid} is missing a Severity or Status field")
findings.append((library, fid, sev.group(1), title, status.group(1).strip()))
return header, findings
def finding_number(finding):
return int(re.search(r"-(\d+)$", finding[1]).group(1))
def build_readme(libraries, per_library):
pending = sorted(
(f for fs in per_library.values() for f in fs[1] if f[4] in PENDING_STATUSES),
key=lambda f: (SEVERITY_ORDER.get(f[2], 9), f[0], finding_number(f)),
)
reviewed = sum(1 for lib in libraries if per_library[lib][0][0] is not None)
def severity_total(sev):
return sum(1 for f in pending if f[2] == sev)
def open_count(library, sev):
return sum(1 for f in per_library[library][1]
if f[2] == sev and f[4] in PENDING_STATUSES)
lines = []
add = lines.append
add("# Code Reviews")
add("")
add("Comprehensive, per-library code reviews of the `ZB.MOM.WW.*` shared libraries hosted")
add("in this repo. Each library (one self-contained `.slnx` at the repo root) has its own")
add("folder containing a `findings.md`. This README is the aggregated index — the single")
add("place to see all outstanding work.")
add("")
add("> Generated by `regen-readme.py` from the per-library `findings.md` files. Do not")
add("> edit by hand — edit the findings files and re-run the script.")
add("")
add("## How it works")
add("")
add("- Reviews are performed one library at a time against a fixed checklist.")
add("- Each library is reviewed against its normalized component spec under `components/`.")
add("- Every finding is recorded in the library's `findings.md` with a severity and status.")
add("- Findings are **never deleted** — they are closed by changing their status, keeping")
add(" a full audit trail.")
add("- This README aggregates every **pending** finding (`Open` / `In Progress`) across all")
add(" libraries.")
add("")
add("See **[REVIEW-PROCESS.md](REVIEW-PROCESS.md)** for the full procedure: the review")
add("checklist, severity definitions, finding format, the library → component-spec mapping,")
add("and how to mark items resolved.")
add("")
add("## Layout")
add("")
add("```")
add("code-reviews/")
add("├── README.md # this file — process overview + pending findings")
add("├── REVIEW-PROCESS.md # how to perform a review and track findings")
add("├── regen-readme.py # regenerates this README from the findings files")
add("├── _template/findings.md # copy-this template for a library review")
add("└── <Library>/findings.md # one folder per ZB.MOM.WW.* shared library")
add("```")
add("")
add("## Summary")
add("")
add(f"{reviewed} of {len(libraries)} libraries reviewed. "
f"{len(pending)} pending finding{'s' if len(pending) != 1 else ''} across all libraries.")
add("")
add("| Severity | Open findings |")
add("|----------|---------------|")
for sev in ("Critical", "High", "Medium", "Low"):
add(f"| {sev} | {severity_total(sev)} |")
add(f"| **Total** | **{len(pending)}** |")
add("")
add("## Library Status")
add("")
add("| Library | Last reviewed | Commit | Open (C/H/M/L) | Open | Total |")
add("|---------|---------------|--------|----------------|------|-------|")
for library in libraries:
counts = [open_count(library, s) for s in ("Critical", "High", "Medium", "Low")]
last_reviewed, commit = per_library[library][0]
last_cell = last_reviewed if last_reviewed else NOT_REVIEWED
commit_cell = f"`{commit}`" if commit else NOT_REVIEWED
add(f"| [{library}]({library}/findings.md) | {last_cell} | {commit_cell} "
f"| {counts[0]}/{counts[1]}/{counts[2]}/{counts[3]} "
f"| {sum(counts)} | {len(per_library[library][1])} |")
add("")
add("## Pending Findings")
add("")
add("Every `Open` / `In Progress` finding across all libraries, highest severity first.")
add("Resolved findings drop off this list but remain recorded in their library's")
add("`findings.md` (see [REVIEW-PROCESS.md](REVIEW-PROCESS.md) §4–§5). Full detail —")
add("description, location, recommendation — lives in the library's `findings.md`.")
add("")
for sev in ("Critical", "High", "Medium", "Low"):
rows = [f for f in pending if f[2] == sev]
add(f"### {sev} ({len(rows)})")
add("")
if not rows:
add("_None open._")
add("")
continue
add("| ID | Library | Title |")
add("|----|---------|-------|")
for library, fid, _, title, _ in rows:
add(f"| {fid} | [{library}]({library}/findings.md) | {title} |")
add("")
return "\n".join(lines)
def main():
check = "--check" in sys.argv[1:]
libraries = discover_libraries()
per_library = {m: parse_findings(m) for m in libraries}
content = build_readme(libraries, per_library)
readme_path = os.path.join(BASE, "README.md")
pending = sum(1 for fs in per_library.values()
for f in fs[1] if f[4] in PENDING_STATUSES)
total = sum(len(fs[1]) for fs in per_library.values())
if check:
current = open(readme_path).read() if os.path.exists(readme_path) else ""
if current != content:
print("README.md is stale — run: python3 code-reviews/regen-readme.py")
sys.exit(1)
print(f"README.md is up to date ({pending} pending / {total} total).")
return
open(readme_path, "w").write(content)
print(f"README.md regenerated — {pending} pending, {total} total findings "
f"across {len(libraries)} libraries.")
if __name__ == "__main__":
main()