Establishes a per-module code review workflow under code-reviews/ and
records the 2026-05-16 baseline review (commit 9c60592): 241 findings
across all src/ modules (6 Critical, 46 High, 100 Medium, 89 Low).
This is the clean starting point for remediation work.
5.8 KiB
Code Review Process
This document describes how to perform a comprehensive, per-module code review of the ScadaLink codebase and how to track findings to resolution.
A module is one buildable project under src/ (e.g. src/ScadaLink.TemplateEngine).
Each module has its own folder under code-reviews/ containing a single findings.md.
1. Before you start
- Pick the module to review. Its folder is
code-reviews/<Module>/where<Module>is the project name with theScadaLink.prefix stripped. - Identify the design context for the module:
- Its component design doc:
docs/requirements/Component-<Name>.md. - The relevant Key Design Decisions in
CLAUDE.md. docs/requirements/HighLevelReqs.mdfor cross-cutting requirements.
- Its component design doc:
- 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. - Open
code-reviews/<Module>/findings.mdand fill in the header table (reviewer, date, commit SHA).
2. Review checklist
Work through every category below for the module. 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.
- Correctness & logic bugs — off-by-one, null handling, incorrect conditionals, misuse of APIs, broken edge cases.
- Akka.NET conventions — supervision strategies (Resume for coordinators, Stop
for short-lived actors),
Tellfor hot paths /Askonly at system boundaries, message immutability, no blocking on non-blocking dispatchers, nosender/thiscaptured in closures (PipeToinstead), correlation IDs on request/response. - Concurrency & thread safety — shared mutable state, actor state mutated only on the actor thread, race conditions, correct use of async/await.
- Error handling & resilience — exception paths, store-and-forward integration, reconnect/retry logic, failover behaviour, transient vs permanent error classification, graceful degradation.
- Security — authentication/authorization checks, input validation, the script
trust model (forbidden APIs:
System.IO,Process,Threading,Reflection, raw network), secret handling, SQL/LDAP injection, logging of sensitive data. - Performance & resource management —
IDisposabledisposal, stream/connection lifetimes, buffering and back-pressure, unnecessary allocations, N+1 queries. - Design-document adherence — does the code match
Component-<Name>.mdand the relevant CLAUDE.md decisions? Flag both code that drifts from the design and design docs that are now stale. - Code organization & conventions — persistence-ignorant POCO entities in Commons, repository interfaces in Commons / implementations in ConfigurationDatabase, namespace hierarchy, Options pattern (options classes owned by component projects), additive-only message contract evolution.
- Testing coverage — are the module's behaviours covered by tests in
tests/? Note untested critical paths and missing edge-case tests. - Documentation & comments — XML doc accuracy, misleading or stale comments, undocumented non-obvious behaviour.
3. Recording findings
Add one entry per finding to the ## Findings section of the module's findings.md,
using the entry format in _template/findings.md.
- Finding ID —
<Module>-NNN, numbered sequentially within the module and never reused (e.g.TemplateEngine-001). IDs are permanent even after resolution. - Severity:
- Critical — data loss, security breach, crash/deadlock, or cluster-wide outage.
- High — incorrect behaviour with significant impact; 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 module 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 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-module view. After any review or
status change, update it:
- Pending Findings table — add/remove rows so it lists exactly the
OpenandIn Progressfindings across all modules, sorted by severity. - Module Status table — update the row for the reviewed module (last-reviewed date, commit, open-finding count, review status).
The base README must always agree with the per-module findings.md files — they are
the source of truth; the README is the aggregated index.
6. Re-reviewing a module
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.