33915c9e4d
docs/Raw.md (the /raw project tree: lazy tree, endpoint→DeviceConfig split, manual/CSV/browse authoring, Calculation driver, routed-flow retirement); CLAUDE.md AdminUI section notes /raw + DriverTypeNames rewire + Calculation driver; PR body with the 7-item live-gate evidence. Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
5.1 KiB
5.1 KiB
v3 Batch 2 — /raw project-tree AdminUI + Calculation driver
Implements docs/plans/2026-07-15-v3-batch2-raw-ui-calculation-plan.md (Track 0 + WP1–WP8),
executed via the /v3-batch 2 coordinator: contracts-first fan-out, worktree-isolated Opus
agents per wave, a code-reviewer pass + green build/test after each wave, then the
non-negotiable 7-item live gate on docker-dev.
What landed
- Track 0 — reusable
ContextMenu(right-click +⋯, keyboard/focus); RFC-4180CsvParser/CsvWriter;DriverTypeNamesconstants + a reflection-discovery guard;CalculationEvaluatorcore (VirtualTag-evaluator parity). - Wave A —
IRawTreeService/RawTreeService(lazy tree + mutations, integrity guards, rename-warnings);/rawpage + lazyRawTreewith per-node context menus. - Wave B — driver→embeddable-form refactor +
DriverConfigModal/DeviceModal(endpoint→DeviceConfig, Test-connect via merged config); manual tag entry + tag edit modal +Calculationtag editor; CSV import (staged review grid) / export; all wired into the tree (name/confirm/driver-type dialogs + post-mutation refresh). - Wave C — browse re-target (two-tier gate, merged-config feed, commit → raw tags with
address-field mapping + folder mirroring);
Calculationdriver (IDependencyConsumer+ mux adapter, timer + change triggers,DraftValidatorscriptId + cycle gates);DriverTypeNamesrewire + retirement of the routed driver flow.
Address space stays dark (values light up in Batch 4). Full solution builds 0 errors;
AdminUI.Tests 638 passed / 3 skipped, Runtime.Tests 357 passed, driver + guard suites green.
Reviewer findings fixed in-branch
- Wave B H1 — driver forms still serialized the endpoint into
DriverConfig; stripped the endpoint keys (Modbus/S7/OpcUaClient) soDeviceConfigis the sole source (a 2nd device on a single-Host driver no longer reverts to127.0.0.1). - Wave C HIGH —
CalculationDriver.ReinitializeAsyncignored the new config, so calc tag/script edits were silently inert after a redeploy and the re-register loop was decorative. Now rebuilds the tag/dependency table on reinit and re-registers deps after the delta applies (DeltaAppliednotification, race-free). New redeploy test proves it. - Wave-A/B/0 mediums (auto-expand, friendly create-race/delete failures, discovery-driven
guard, CSV comment). Deferred (documented): pre-existing Modbus/S7 form
TimeSpan↔*MsDTO mismatch; CSV alarm-subfield/flag-precedence edge cases; OpcUaClient endpoint precedence; unusedLoadMergedProbeConfigAsync; refresh collapses sibling expansion.
Live /run gate (docker-dev :9200, both central nodes rebuilt)
- Authoring + Test-connect —
/raw→ New Modbus drivergate-modbus(form body renders,PLC family/MELSECenum dropdowns correct) → Device1 endpoint10.100.0.35:5020inDeviceConfig→ Test connect OK · 94 ms against the live Modbus fixture; SQL confirms endpoint inDeviceConfig({"Host":"10.100.0.35","Port":5020,"UnitId":1}). - Historian-tagname deploy block — a historized tag with a 260-char effective tagname →
POST /api/deployments422[HistorianTagnameTooLong] tag 'TAG-gatelong' … is 260 chars (max 255); shortened override → 202 Accepted. - CSV round-trip + bad-enum — export produces the exact column dictionary
(
…,Region,Address,ModbusDataType,ByteOrder,…); importing 1 valid + 1 bad-enum row → review grid "2 rows, 1 valid, 1 invalid", row-2 error "Column 'ModbusDataType': 'NOTATYPE' is not a valid ModbusDataType (expected one of: Bool, Int16, UInt16, …)", Commit disabled (all-or-nothing; SQL confirms nothing committed); a valid-only import → Commit →ImportedTaglands with typed columns assembled intoTagConfig. - Browse-commit — OpcUaClient device → opc-plc (
opc.tcp://10.100.0.35:50000): two-tier gate enabled browse, merged config connected, real tree walked (NetworkSet/…/OpcPlc); multi-selected 2 leaves with "create matching tag-groups" → raw tags land under the mirroredBasicgroup with DataType + the browse ref in thenodeIdaddress field (nsu=…;s=AlternatingBoolean), not an identity key. - Calculation deploy + cycle gate — a calc tag reading a Modbus RawPath deploys 202;
a 2-cycle (
calc1/Engine/A↔calc1/Engine/B) → 422[CalculationDependencyCycle] … (members: calc1/Engine/A, calc1/Engine/B); clean redeploy 202, no crash loops (both central nodes stable; only a deploy-reject WRN in the log). - Rename warning — renaming
gate-modbus→gate-modbus-renamedfired the warning modal "1 historized tag beneath this node will change its RawPath (historian tagname)…". - Retired routes —
/clusters/{id}/drivers,…/new,…/new/{slug},…/{id}all return 404;/raw+/unsstill 200.
Docs
docs/Raw.md (new — the /raw authoring tree + endpoint split + CSV + Calculation +
retirement note); CLAUDE.md AdminUI section updated; the Calculation mini-design remains the
driver's authority.