docs(code-review): record SMS-feature review findings + reconcile NotificationService doc

Per-module code review of the SMS notifications feature (reviewed at d6ead8ae) following
code-reviews/REVIEW-PROCESS.md. 19 findings across 7 modules — 1 High, 5 Medium, 13 Low:

- ManagementService-024 (High): provider-config updates Admin-gated to match the UI.
- ConfigurationDatabase-025, CentralUI-034/035, ManagementService-025 (Medium): migration
  data-safety guard, type-aware recipient badge, FromNumber-optional (Messaging-Service-only),
  empty-token-clear guard.
- Remaining Low: secret-encryption + diff + dispatch + factory + contract tests, truncation,
  ctor guard, reserved retry-field docs.
- Won't Fix: Transport-015/016 (shared repo-wide import patterns, not SMS-specific),
  Commons-026 (breaking ergonomics-only change). Deferred: ConfigurationDatabase-027 (live-SQL
  migration test).

All findings closed (0 pending). README.md regenerated; Component-NotificationService.md
updated for the FromNumber-optional + reserved-retry-fields outcomes.
This commit is contained in:
Joseph Doherty
2026-06-19 15:30:32 -04:00
parent 33e1802e6d
commit 4307c38117
9 changed files with 579 additions and 26 deletions
+86 -2
View File
@@ -5,9 +5,9 @@
| Module | `src/ZB.MOM.WW.ScadaBridge.Commons` |
| Design doc | `docs/requirements/Component-Commons.md` |
| Status | Reviewed |
| Last reviewed | 2026-05-28 |
| Last reviewed | 2026-06-19 |
| Reviewer | claude-agent |
| Commit reviewed | `1eb6e97` |
| Commit reviewed | `d6ead8ae` |
| Open findings | 2 |
## Summary
@@ -1155,3 +1155,87 @@ fields on positional records MUST be added at the end of the parameter list AND
carry a `= null` (or other safe) default value, so existing positional construction
sites keep compiling. Apply that rule retroactively to `TrackingStatusSnapshot` and any
other recent record that did not adopt it. No behavioral change required.
#### Re-review 2026-06-19 (commit `d6ead8ae`) — SMS notifications feature
Per-module review of the SMS (Twilio) notifications feature (#21 Notification Outbox / #8
Notification Service slice). Three Low-severity findings in Commons; all closed. The new
`SmsConfiguration` POCO, `NotificationType.Sms`, the `NotificationRecipient` `ForEmail`/`ForSms`
factories, and the additive message-contract changes all follow the established conventions.
### Commons-024 — `NotificationRecipient` public constructor name-guard weaker than the factories
| | |
|--|--|
| Severity | Low |
| Category | Correctness & logic bugs |
| Status | Resolved |
| Location | `src/ZB.MOM.WW.ScadaBridge.Commons/Entities/Notifications/NotificationRecipient.cs:21-25` |
**Description**
The public `NotificationRecipient(string name, string emailAddress)` constructor validated `name`
with a null-only check (`name ?? throw`), while the `ForEmail`/`ForSms` factories reject
null-or-whitespace names. A caller using the public ctor directly could produce a recipient with a
whitespace name, an invariant the factories forbid. (EF materializes via the private parameterless
ctor + property injection, so this ctor is reached only by intentional email-path callers.)
**Recommendation**
Tighten the public ctor's name guard to `IsNullOrWhiteSpace` to match the factories.
**Resolution**
Resolved 2026-06-19 (commit `cd8e4872`): the public ctor now throws `ArgumentException` on a
null-or-whitespace name, matching `ForEmail`. Locked by `NotificationRecipientTests` (commit `a9393c89`).
### Commons-025 — No unit tests for `NotificationRecipient.ForEmail`/`ForSms` factory invariants
| | |
|--|--|
| Severity | Low |
| Category | Testing coverage |
| Status | Resolved |
| Location | `tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Entities/NotificationRecipientTests.cs` |
**Description**
The recipient construction invariants (email-only for `ForEmail`, phone-only for `ForSms`,
non-blank name on every path) were exercised only transitively via ManagementActor tests, with no
focused Commons-layer unit tests.
**Recommendation**
Add a `NotificationRecipientTests` covering both factories' happy paths, the null/whitespace guards,
and the contact-field exclusivity.
**Resolution**
Resolved 2026-06-19 (commit `a9393c89`): added `NotificationRecipientTests` (14 cases) covering
`ForEmail`/`ForSms` happy paths, contact-field exclusivity, null/whitespace name guards, and the
public-ctor guards.
### Commons-026 — `Create/UpdateNotificationListCommand.RecipientEmails` non-nullable even for SMS lists
| | |
|--|--|
| Severity | Low |
| Category | Code organization & conventions |
| Status | Won't Fix |
| Location | `src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Management/NotificationCommands.cs:7-8` |
**Description**
`CreateNotificationListCommand`/`UpdateNotificationListCommand` carry `RecipientEmails` as a
required positional parameter even when `Type = Sms`, where it is semantically irrelevant (the
handler ignores it and reads `RecipientPhones`). This is an ergonomics wart, not a correctness bug.
**Recommendation**
Optionally default `RecipientEmails` to an empty list, or normalize null→empty in the handler.
**Resolution**
Won't Fix (2026-06-19): not a correctness defect — the handler already ignores `RecipientEmails`
for SMS lists. Changing a required positional parameter to defaulted/nullable is a breaking
contract change for existing callers for a pure-ergonomics gain; deferred indefinitely.