fix(modbus): review r3 - one address authority (ModbusTagAddressResolution)
N3: a keyless blob carrying the addressResolved marker was served from its string by the driver but saved as HR[0] by the editor model / CSV path. The precedence rule now lives in ONE pure resolver in Driver.Modbus.Contracts (ModbusTagAddressResolution.Classify/Resolve): keys when region+address are both present, else a string-only addressString resolved with the driver's family (refused when it cannot parse), else refused. The marker never decides. Consumers that now ask it instead of restating it: the driver's tag reader (ModbusTagDefinitionFactory.FromTagConfig), the deploy gate (Inspect / DescribeRejection), the editor model (AddressShape / IsStringOnly / HasKeyAddress / ResolveWith, ToJson stamping, Validate), the CSV export cells and the editor hint. The model writes keys only when it loaded them or a field was authored - never defaults it did not resolve (also closes two divergences the new matrix found: malformed-string+marker and non-string addressString were saved as HR[0]). One table-driven test (ModbusAddressAuthorityAgreementTests) runs 15 persisted shapes through driver, deploy gate, model load/save/Validate and the real CSV export->import under all four families; breaking the CSV export or reverting the model to the marker rule fails it. Minors: m1 CSV address cells keep the string+marker while it still describes them (lossless unchanged round trip), drop it when contradicted, and the review grid reports the drop; m2 the pre-lane test uses the real export residual; m3 unmarked string-only + typed-cell case added; m4 stale docs/summary and the unused factory parameter removed. Refs #741 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -243,19 +243,36 @@ than asking users to rewrite spreadsheets.
|
||||
|
||||
## Address strings, families and region/type rules (#741)
|
||||
|
||||
- **One authority: `ModbusTagAddressResolution` (Driver.Modbus.Contracts).** The
|
||||
driver's tag reader, the deploy gate (`Inspect`), the AdminUI editor model
|
||||
(load / save / `Validate` / the hint text) and the CSV import/export all ask
|
||||
it which part of a blob is the address; none restates the rule. Its
|
||||
agreement is pinned by one table-driven test that runs every persisted shape
|
||||
through every consumer (`ModbusAddressAuthorityAgreementTests`).
|
||||
- **Whenever a tag carries both `region` and `address`, those keys are its
|
||||
address** — a classic tag, an editor-pinned tag, and a pre-#741 row that
|
||||
carried an `addressString` beside its keys (the old driver never read the
|
||||
string) all load from the keys, exactly as before, and a family change never
|
||||
remaps them. Only a **string-only** blob (an `addressString` with NO
|
||||
`region`/`address` — CSV / API authoring) is resolved through
|
||||
`ModbusAddressParser` with the **driver's** `Family` / `MelsecSubFamily`; the
|
||||
AdminUI never stamps default keys onto it, so it cannot collapse onto HR[0],
|
||||
and a family that cannot parse it refuses the tag (BadNodeIdUnknown).
|
||||
`ModbusAddressParser` with the **driver's** `Family` / `MelsecSubFamily`; a
|
||||
family that cannot parse it refuses the tag (BadNodeIdUnknown). It is never
|
||||
served as HR[0].
|
||||
- `"addressResolved": true` is editor display / CSV state only: it never makes
|
||||
keys authoritative, and a marker on a blob WITHOUT keys is ignored (the blob
|
||||
is string-only) and dropped on the next editor save.
|
||||
- The AdminUI never writes default keys it did not resolve: the editor model
|
||||
stamps `region`/`address`/type only when the loaded blob had the keys, or when
|
||||
a field is set (hand edit, CSV address cell, Resolve). A string-only,
|
||||
non-string-`addressString` or address-less blob keeps its keys unwritten, and
|
||||
its CSV export leaves the address cells blank.
|
||||
- The editor's "Resolve with driver family" persists the resolved
|
||||
`region`/`address`/type fields plus `"addressResolved": true` (the pinned
|
||||
state). Editing a resolved field by hand — in the editor or a typed CSV
|
||||
address cell — drops the string and the marker.
|
||||
state). Editing a resolved field by hand in the editor drops the string and
|
||||
the marker. A typed CSV address cell keeps them only while the string still
|
||||
describes the cells under some family (so an unchanged export → import of a
|
||||
pinned row is lossless); a contradicting cell drops them, and the import
|
||||
review grid reports that column as an override.
|
||||
- Coils / DiscreteInputs carry only Bool. A bit-region tag persisted with a
|
||||
register `dataType` (the pre-#741 editor saved `Int16`) is coerced to Bool,
|
||||
never refused. A register region with `Bool` is refused (use
|
||||
|
||||
Reference in New Issue
Block a user