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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user