Files
lmxopcua/code-reviews/Core.Scripting.Abstractions/findings.md
T
Joseph Doherty 98b27fc1b6 fix(code-review): resolve Batch 1 open findings (AdminUI auth, AlarmHistorian dispose guards, docs)
- AdminUI-001: gate Script editor pages at Administrator,Designer + loosen ScriptAnalysis backend to match
- AdminUI-004: explicit [Authorize] on FleetStatus/Alert/ScriptLog hubs
- Core.AlarmHistorian-014: ObjectDisposedException guards on GetStatus/RetryDeadLettered (+ regression test)
- Core.Scripting.Abstractions-004/-007: Deadband tolerance doc + stale ScriptedAlarms.md path
- Host-003: correct config-overlay precedence in ServiceHosting.md
- Configuration-014: LdapGroupRoleMapping collation-dependency doc
- Driver.TwinCAT.Contracts-002: Structure enum doc (discovery-only sentinel)
2026-06-20 22:30:33 -04:00

211 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Code Review — Core.Scripting.Abstractions
<!-- Template for a per-module findings file. Copy to code-reviews/<Module>/findings.md.
See ../../REVIEW-PROCESS.md for the full process. The base README.md is generated
from these files by regen-readme.py — do not edit README.md by hand. -->
| Field | Value |
|---|---|
| Module | `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions` |
| Reviewer | Claude Code |
| Review date | 2026-06-19 |
| Commit reviewed | `7286d320` |
| Status | Reviewed |
| Open findings | 0 |
## Checklist coverage
A comprehensive review completes every category, recording "No issues found" where
a category produced nothing rather than leaving it blank.
| # | Category | Result |
|---|---|---|
| 1 | Correctness & logic bugs | 1 finding (Core.Scripting.Abstractions-004) |
| 2 | OtOpcUa conventions | No issues found |
| 3 | Concurrency & thread safety | No issues found |
| 4 | Error handling & resilience | No issues found |
| 5 | Security | No issues found |
| 6 | Performance & resource management | No issues found |
| 7 | Design-document adherence | 1 finding (Core.Scripting.Abstractions-007) |
| 8 | Code organization & conventions | No issues found |
| 9 | Testing coverage | No issues found |
| 10 | Documentation & comments | 5 findings (001003, 005006) |
## Findings
<!-- One ### entry per finding. IDs are <Module>-NNN, sequential within the module,
never reused. Findings are never deleted — close them by changing Status and
completing Resolution. -->
### Core.Scripting.Abstractions-001
| Field | Value |
|---|---|
| Severity | Low |
| Category | Documentation & comments |
| Location | `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/AlarmPredicateContext.cs:43,46` |
| Status | Resolved |
**Description:** `AlarmPredicateContext.GetTag` uses the magic constant `0x80340000u` twice with no
inline comment. The sibling `VirtualTagContext.GetTag` annotates both sites with
`/* BadNodeIdUnknown */`, making the intent immediately clear. The inconsistency makes the alarm
context harder to audit for correctness.
**Recommendation:** Add `/* BadNodeIdUnknown */` inline comments matching the pattern in
`VirtualTagContext.cs:55,58`.
**Resolution:** Applied inline — added `/* BadNodeIdUnknown */` comments to both `0x80340000u`
literals in `AlarmPredicateContext.GetTag`. Verified by build (no test project for this module).
2026-06-19.
---
### Core.Scripting.Abstractions-002
| Field | Value |
|---|---|
| Severity | Low |
| Category | Documentation & comments |
| Location | `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/AlarmPredicateContext.cs:14` |
| Status | Resolved |
**Description:** The `<remarks>` block opens with "Per Phase 7 plan Shape A decision...". The
project-wide rename (master commit `40e8a23e`) retired the "Phase 7" prefix for the address-space
pipeline; comments referencing it by that name are stale and confuse new readers. The authoritative
plan document is `docs/v2/implementation/phase-7-scripting-and-alarming.md` (decision row 4, Shape
A), so the relevant fix is to cite the design doc rather than the internal plan-phase label.
**Recommendation:** Replace "Per Phase 7 plan Shape A decision" with "Per the scripting design
(see `docs/v2/implementation/phase-7-scripting-and-alarming.md`, decision row 4)".
**Resolution:** Applied inline — updated the stale "Phase 7 plan Shape A decision" reference to
cite the design doc directly. Verified by build (no test project for this module). 2026-06-19.
---
### Core.Scripting.Abstractions-003
| Field | Value |
|---|---|
| Severity | Low |
| Category | Documentation & comments |
| Location | `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/ScriptContext.cs:9,10` |
| Status | Resolved |
**Description:** The `ScriptContext` summary comment reads "Phase 7 plan decision #6: scripts can
read any tag, write only to virtual tags...". The "Phase 7 plan" label is stale after the global
rename. Decision #6 in `docs/v2/plan.md` remains the correct reference, but the wording should
match the current naming convention.
**Recommendation:** Replace "Phase 7 plan decision #6" with "plan decision #6 (see
`docs/v2/plan.md`)".
**Resolution:** Applied inline — updated the stale "Phase 7 plan decision #6" reference to use the
current naming convention. Verified by build (no test project for this module). 2026-06-19.
---
### Core.Scripting.Abstractions-004
| Field | Value |
|---|---|
| Severity | Low |
| Category | Correctness & logic bugs |
| Location | `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/ScriptContext.cs:84` |
| Status | Resolved |
**Description:** `ScriptContext.Deadband` has no guard or documentation for invalid `tolerance`
values. A negative `tolerance` makes `Math.Abs(current - previous) > tolerance` trivially `true`
for all finite inputs (any absolute value exceeds a negative number), so `Deadband(x, y, -1.0)`
always reports a change regardless of the actual difference — silently inverting the intended
semantics. A NaN `tolerance` makes the comparison always `false` (no change ever detected). Neither
case is caught by the compiler and there is no runtime warning, so script authors have no feedback
when they supply an invalid threshold.
**Recommendation:** Document the behavior clearly in the `<param name="tolerance">` XML doc. If a
design decision allows it, add an `ArgumentOutOfRangeException` guard for `tolerance < 0`, but this
changes the public API contract for authored scripts and needs a plan-level decision. Minimum fix
(doc-only, zero-risk):
```
/// <param name="tolerance">The minimum change magnitude to detect (must be &gt;= 0).
/// Negative values cause the function to always return true; NaN always returns false.</param>
```
**Resolution:** Applied doc-only fix — updated the `<param name="tolerance">` XML doc in
`ScriptContext.cs:90` to document that negative values always return true and NaN always returns
false. No guard added (API contract change deferred per owner decision). 2026-06-20.
---
### Core.Scripting.Abstractions-005
| Field | Value |
|---|---|
| Severity | Low |
| Category | Documentation & comments |
| Location | `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/VirtualTagContext.cs:21` |
| Status | Resolved |
**Description:** The `<remarks>` second paragraph ends with "Mutable state across runs is a future
decision (e.g. a dedicated `ctx.Memory` dictionary); not in scope for Phase 7." The "Phase 7"
label is stale (see findings 002 and 003). The forward-looking note itself is still valid.
**Recommendation:** Replace "not in scope for Phase 7" with "not currently in scope".
**Resolution:** Applied inline — removed the stale Phase 7 label. Verified by build (no test
project for this module). 2026-06-19.
---
### Core.Scripting.Abstractions-006
| Field | Value |
|---|---|
| Severity | Low |
| Category | Documentation & comments |
| Location | `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/ScriptContext.cs:35-36,55-58` |
| Status | Resolved |
**Description:** The `<summary>` for `ScriptContext.GetTag` describes the path syntax as
"forward-slash delimited, matching the Equipment-namespace browse tree" but makes no mention of the
`{{equip}}` equipment-relative token introduced in master commit `27c34a55`. Operators reading the
XML doc for IntelliSense will not know the token exists. The `SetVirtualTag` remarks similarly omit
it.
**Recommendation:** Add a note to the `GetTag` (and `SetVirtualTag`) `<remarks>`: "The reserved
`{{equip}}` token may appear in the path literal; it is substituted with the owning equipment's
tag-base prefix at deployment time. See `docs/ScriptEditor.md` — Equipment-relative tag paths."
**Resolution:** Applied inline — added `{{equip}}` token mention to `GetTag` and `SetVirtualTag`
remarks in `ScriptContext.cs`. Verified by build (no test project for this module). 2026-06-19.
---
### Core.Scripting.Abstractions-007
| Field | Value |
|---|---|
| Severity | Low |
| Category | Design-document adherence |
| Location | `docs/ScriptedAlarms.md:298` |
| Status | Resolved |
**Description:** `docs/ScriptedAlarms.md` line 298 lists the file path as
`src/Core/ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms/AlarmPredicateContext.cs`. The file was moved to
`src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/AlarmPredicateContext.cs` as part of the
A0 memory-reduction plan (`docs/plans/2026-06-07-virtualtag-script-memory.md`, step 1 `git mv`
list). The stale path sends readers to a non-existent location. The namespace was intentionally
preserved (`Core.ScriptedAlarms`) so no `using` changes were needed — the file location is the
only thing that changed.
**Recommendation:** Update `docs/ScriptedAlarms.md` line 298:
```
- `src/Core/ZB.MOM.WW.OtOpcUa.Core.Scripting.Abstractions/AlarmPredicateContext.cs` — script-side `ScriptContext` (read-only, write rejected)
```
**Resolution:** Updated `docs/ScriptedAlarms.md` line 298 — replaced the stale
`Core.ScriptedAlarms/AlarmPredicateContext.cs` path with the correct
`Core.Scripting.Abstractions/AlarmPredicateContext.cs` path. Verified the file exists at the new
location before editing. 2026-06-20.