docs(code-reviews): re-review batch 1 at 39d737e — CentralUI, CLI, ClusterInfrastructure, Commons, Communication
17 new findings: CentralUI-020..025, CLI-014..016, ClusterInfrastructure-009..010, Commons-013..014, Communication-012..015.
This commit is contained in:
@@ -5,10 +5,10 @@
|
||||
| Module | `src/ScadaLink.CLI` |
|
||||
| Design doc | `docs/requirements/Component-CLI.md` |
|
||||
| Status | Reviewed |
|
||||
| Last reviewed | 2026-05-16 |
|
||||
| Last reviewed | 2026-05-17 |
|
||||
| Reviewer | claude-agent |
|
||||
| Commit reviewed | `9c60592` |
|
||||
| Open findings | 0 |
|
||||
| Commit reviewed | `39d737e` |
|
||||
| Open findings | 3 |
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -31,8 +31,26 @@ ID-keyed, flag-based surface. Test coverage exercises `OutputFormatter`, `CliCon
|
||||
`CommandHelpers.HandleResponse`, but the HTTP client, the `debug stream` path, the JSON
|
||||
argument parsing, and the command-tree wiring are untested.
|
||||
|
||||
#### Re-review 2026-05-17 (commit `39d737e`)
|
||||
|
||||
All 13 prior findings are confirmed resolved — the resilience gaps, the dead format
|
||||
configuration, the credential-handling weakness, and the test-coverage holes have all
|
||||
been closed, and the test suite has grown substantially (`CommandTreeTests`,
|
||||
`ManagementHttpClientTests`, `DebugStreamTests`, etc.). The CLI's runtime behaviour is now
|
||||
solid. This re-review walked all 14 command groups against the full checklist and found
|
||||
three new issues, all rooted in **update-command and design-document drift** rather than
|
||||
runtime defects: every `update` command requires the entity's "core" fields (`--name`,
|
||||
`--script`) even though the design doc presents them as optional, so a partial update is
|
||||
impossible (CLI-014); the design doc's command surface has drifted again in two specific
|
||||
places — `template composition delete` and the `data-connection` config flags (CLI-015);
|
||||
and `WriteAsTable` derives table columns from only the first array element, silently
|
||||
dropping columns for any later element with a different shape (CLI-016). No
|
||||
Critical/High issues; the module remains healthy.
|
||||
|
||||
## Checklist coverage
|
||||
|
||||
_Original review (2026-05-16, `9c60592`):_
|
||||
|
||||
| # | Category | Examined | Notes |
|
||||
|---|----------|----------|-------|
|
||||
| 1 | Correctness & logic bugs | ☑ | Format precedence is broken (CLI-001); empty/non-JSON success bodies crash table rendering (CLI-002, CLI-003). |
|
||||
@@ -46,6 +64,21 @@ argument parsing, and the command-tree wiring are untested.
|
||||
| 9 | Testing coverage | ☑ | No tests for `ManagementHttpClient`, `DebugCommands`, command-tree wiring, or JSON argument parsing (CLI-013). |
|
||||
| 10 | Documentation & comments | ☑ | `Component-CLI.md` mismatch (CLI-007); the in-repo `README.md` is reasonably accurate. Minor exit-code doc mismatch (CLI-009). |
|
||||
|
||||
_Re-review (2026-05-17, `39d737e`):_
|
||||
|
||||
| # | Category | Examined | Notes |
|
||||
|---|----------|----------|-------|
|
||||
| 1 | Correctness & logic bugs | ☑ | Update commands require "core" fields, blocking partial updates (CLI-014); `WriteAsTable` headers derived from first array element only (CLI-016). |
|
||||
| 2 | Akka.NET conventions | ☑ | Not applicable — pure HTTP/SignalR client. No issues. |
|
||||
| 3 | Concurrency & thread safety | ☑ | `debug stream` concurrency now resolved via `DebugStreamHelpers` (CLI-011/012). No new issues. |
|
||||
| 4 | Error handling & resilience | ☑ | Malformed-URL / malformed-JSON / connect-cancellation paths all hardened (CLI-004/005/010). No new issues. |
|
||||
| 5 | Security | ☑ | Env-var credential fallback in place (CLI-006). Basic Auth over HTTP is by design. No new issues. |
|
||||
| 6 | Performance & resource management | ☑ | `CancellationTokenSource` now `using`-scoped (CLI-011). No new issues. |
|
||||
| 7 | Design-document adherence | ☑ | Two residual command-surface drifts: `template composition delete` and `data-connection --primary-config` (CLI-015). |
|
||||
| 8 | Code organization & conventions | ☑ | Consistent and clean; option construction centralised in `CliOptions`. No new issues. |
|
||||
| 9 | Testing coverage | ☑ | Substantially expanded (`CommandTreeTests`, `ManagementHttpClientTests`, `DebugStreamTests`). No new gaps. |
|
||||
| 10 | Documentation & comments | ☑ | XML docs accurate. `Component-CLI.md` drift folded into CLI-015. |
|
||||
|
||||
## Findings
|
||||
|
||||
### CLI-001 — `SCADALINK_FORMAT` env var and config-file format are dead; format precedence broken
|
||||
@@ -537,3 +570,121 @@ Resolved 2026-05-16 (commit pending). Coverage gaps confirmed and closed:
|
||||
`InstanceCommands.TryParseBindings`/`TryParseOverrides` and covered by
|
||||
`InstanceArgumentParsingTests` under CLI-005.
|
||||
The CLI test suite went from 42 to 77 passing tests.
|
||||
|
||||
### CLI-014 — `update` commands require "core" fields, making partial updates impossible
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| Severity | Medium |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Open |
|
||||
| Location | `src/ScadaLink.CLI/Commands/TemplateCommands.cs:77`, `src/ScadaLink.CLI/Commands/SiteCommands.cs:86`, `src/ScadaLink.CLI/Commands/ExternalSystemCommands.cs:40-42`, `src/ScadaLink.CLI/Commands/DataConnectionCommands.cs:39-40`, `src/ScadaLink.CLI/Commands/NotificationCommands.cs:40-41`, `src/ScadaLink.CLI/Commands/ApiMethodCommands.cs:79` |
|
||||
|
||||
**Description**
|
||||
|
||||
The design doc presents `update` commands with all non-`--id` fields as optional, e.g.
|
||||
`template update --id <id> [--name <name>] [--description <desc>] [--parent-id <id>]`
|
||||
(`Component-CLI.md:62`) and `api-method update --id <id> [--script <code>] ...`
|
||||
(`Component-CLI.md:224`). The implementation contradicts this: the update commands mark
|
||||
the entity's "core" fields as `Required = true`, so the user must always re-supply them:
|
||||
|
||||
- `template update` — `--name` is `Required = true` (`TemplateCommands.cs:77`).
|
||||
- `site update` — `--name` is `Required = true` (`SiteCommands.cs:86`).
|
||||
- `external-system update` — `--name`, `--endpoint-url`, `--auth-type` are all
|
||||
`Required = true` (`ExternalSystemCommands.cs:40-42`).
|
||||
- `data-connection update` — `--name`, `--protocol` are `Required = true`
|
||||
(`DataConnectionCommands.cs:39-40`).
|
||||
- `notification update` — `--name`, `--emails` are `Required = true`
|
||||
(`NotificationCommands.cs:40-41`).
|
||||
- `api-method update` — `--script` is `Required = true` (`ApiMethodCommands.cs:79`).
|
||||
- The same pattern applies to `template attribute/alarm/script update`
|
||||
(`TemplateCommands.cs:164-165`, `246-248`, `332-334`) and `role-mapping update`
|
||||
(`SecurityCommands.cs:110-111`).
|
||||
|
||||
Because the corresponding `Update*Command` records are whole-replace (they carry the full
|
||||
field set, not a sparse patch), a user who wants to change only one field — e.g. flip an
|
||||
API method's timeout, or rename a template — must look up and re-pass every other field's
|
||||
current value. Omitting any required flag is a hard parse error. This makes scripted,
|
||||
single-field updates (a core CLI/CI use case) awkward and error-prone, and it does not
|
||||
match the documented optional-flag surface.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Decide on one model and align doc + code. Either (a) make the update flags genuinely
|
||||
optional and have the server/`Update*Command` treat a null field as "leave unchanged"
|
||||
(sparse patch), or (b) if whole-replace is intentional, update `Component-CLI.md` to show
|
||||
these flags as required (no `[...]`) and document that an update replaces the whole
|
||||
entity. Option (a) matches the documented surface and the typical CLI expectation.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved._
|
||||
|
||||
### CLI-015 — `Component-CLI.md` command surface has drifted again in two places
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| Severity | Low |
|
||||
| Category | Design-document adherence |
|
||||
| Status | Open |
|
||||
| Location | `docs/requirements/Component-CLI.md:75`, `docs/requirements/Component-CLI.md:125-126` (vs. `src/ScadaLink.CLI/Commands/TemplateCommands.cs:404-413`, `src/ScadaLink.CLI/Commands/DataConnectionCommands.cs:41`, `:86`) |
|
||||
|
||||
**Description**
|
||||
|
||||
CLI-007 regenerated the doc's "Command Structure" section, but two specific drifts remain
|
||||
or were introduced:
|
||||
|
||||
- `Component-CLI.md:75` documents `template composition delete --template-id <id>
|
||||
--instance-name <name>`, but the implementation (`TemplateCommands.cs:404-413`) deletes
|
||||
a composition by its own integer ID via a single `--id` option
|
||||
(`DeleteTemplateCompositionCommand(id)`). The doc's two-flag form does not exist.
|
||||
- `data-connection create` and `update` accept a `--primary-config` option (aliased
|
||||
`--configuration`) for the primary configuration JSON (`DataConnectionCommands.cs:86`,
|
||||
`:41`), but `Component-CLI.md:125-126` lists only `--backup-config` and
|
||||
`--failover-retry-count` — the primary-config flag is absent from the doc.
|
||||
|
||||
A reader following the doc would use a non-existent `template composition delete` form and
|
||||
would not discover the `--primary-config` flag.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Correct `Component-CLI.md:75` to `template composition delete --id <id>`, and add
|
||||
`[--primary-config <json>]` to the documented `data-connection create`/`update` signatures
|
||||
(`Component-CLI.md:125-126`). Also note the `--configuration` alias if aliases are
|
||||
documented elsewhere.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved._
|
||||
|
||||
### CLI-016 — `WriteAsTable` derives columns from the first array element only
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| Severity | Low |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Open |
|
||||
| Location | `src/ScadaLink.CLI/Commands/CommandHelpers.cs:184-200` |
|
||||
|
||||
**Description**
|
||||
|
||||
When rendering a JSON array as a table, `WriteAsTable` builds the header set from
|
||||
`items[0].EnumerateObject()` only (`CommandHelpers.cs:184-186`) and then projects every
|
||||
row against that fixed header list (`:188-198`). If a later element of the array has a
|
||||
different shape — additional properties, or properties the first element lacks — those
|
||||
extra columns are silently dropped from the table and a row missing a header property
|
||||
renders an empty cell. The user sees a table that appears complete but has omitted data,
|
||||
with no indication that columns were discarded. (The JSON output path is unaffected; this
|
||||
only affects `--format table`.) Management API list responses are generally homogeneous,
|
||||
so the practical impact is low, but a heterogeneous array — e.g. a diff or a mixed-status
|
||||
list — would be rendered incorrectly with no warning.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Compute the header set as the union of property names across all array elements (iterate
|
||||
all items, collect distinct property names preserving first-seen order) before projecting
|
||||
rows, so no element's data is silently dropped.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved._
|
||||
|
||||
Reference in New Issue
Block a user