v3 Batch 2 — /raw project-tree AdminUI + Calculation driver #470
Reference in New Issue
Block a user
Delete Branch "v3/batch2-raw-ui"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
v3 Batch 2 —
/rawproject-tree AdminUI +CalculationdriverImplements
docs/plans/2026-07-15-v3-batch2-raw-ui-calculation-plan.md(Track 0 + WP1–WP8),executed via the
/v3-batch 2coordinator: contracts-first fan-out, worktree-isolated Opusagents 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
ContextMenu(right-click +⋯, keyboard/focus); RFC-4180CsvParser/CsvWriter;DriverTypeNamesconstants + a reflection-discovery guard;CalculationEvaluatorcore (VirtualTag-evaluator parity).IRawTreeService/RawTreeService(lazy tree + mutations, integrity guards,rename-warnings);
/rawpage + lazyRawTreewith per-node context menus.DriverConfigModal/DeviceModal(endpoint→
DeviceConfig, Test-connect via merged config); manual tag entry + tag editmodal +
Calculationtag editor; CSV import (staged review grid) / export; all wired intothe tree (name/confirm/driver-type dialogs + post-mutation refresh).
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.Tests638 passed / 3 skipped,Runtime.Tests357 passed, driver + guard suites green.Reviewer findings fixed in-branch
DriverConfig; strippedthe endpoint keys (Modbus/S7/OpcUaClient) so
DeviceConfigis the sole source (a 2nddevice on a single-Host driver no longer reverts to
127.0.0.1).CalculationDriver.ReinitializeAsyncignored the new config, so calctag/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.guard, CSV comment). Deferred (documented): pre-existing Modbus/S7 form
TimeSpan↔*MsDTO mismatch; CSV alarm-subfield/flag-precedence edge cases; OpcUaClient endpoint
precedence; unused
LoadMergedProbeConfigAsync; refresh collapses sibling expansion.Live
/rungate (docker-dev:9200, both central nodes rebuilt)/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 confirmsendpoint in
DeviceConfig({"Host":"10.100.0.35","Port":5020,"UnitId":1}).POST /api/deployments422[HistorianTagnameTooLong] tag 'TAG-gatelong' … is 260 chars (max 255); shortened override → 202 Accepted.(
…,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.opc.tcp://10.100.0.35:50000): two-tiergate enabled browse, merged config connected, real tree walked (NetworkSet/…/OpcPlc);
multi-selected 2 leaves with "create matching tag-groups" → raw tags land under the
mirrored
Basicgroup with DataType + the browse ref in thenodeIdaddress field(
nsu=…;s=AlternatingBoolean), not an identity key.a 2-cycle (
calc1/Engine/A↔calc1/Engine/B) → 422[CalculationDependencyCycle] … (members: calc1/Engine/A, calc1/Engine/B); clean redeploy 202, no crash loops (bothcentral nodes stable; only a deploy-reject WRN in the log).
gate-modbus→gate-modbus-renamedfired the warning modal"1 historized tag beneath this node will change its RawPath (historian tagname)…".
/clusters/{id}/drivers,…/new,…/new/{slug},…/{id}allreturn 404;
/raw+/unsstill 200.Docs
docs/Raw.md(new — the/rawauthoring tree + endpoint split + CSV + Calculation +retirement note);
CLAUDE.mdAdminUI section updated; the Calculation mini-design remains thedriver's authority.
Part 1 — rewire the three DriverType dispatch maps from hand-authored string literals to the canonical DriverTypeNames constants (single source of truth): - TagConfigEditorMap, TagConfigValidator (AdminUI) - EquipmentTagConfigInspector (ControlPlane) This FIXES the live drift ("TwinCat"->TwinCAT, "Focas"->FOCAS). The maps are OrdinalIgnoreCase so behavior is identical; the value is no future drift. Calculation is not added to the inspector (no CalculationTagDefinitionFactory.Inspect). Added TagConfigDriverTypeNameGuardTests pinning the maps to the constants. Part 2 — retire the routed /clusters/{id}/drivers driver-authoring flow (/raw Waves A-C now cover driver/device/tag authoring end-to-end): - Deleted DriverTypePicker, DriverEditRouter, the 8 *DriverPage shells, and the ClusterDrivers list page. - Removed the "Drivers" tab from ClusterNav. Routes /clusters/{id}/drivers* now simply do not exist -> clean 404. - The Forms/DeviceForms bodies, shared driver sections, and address pickers used by the /raw modals are untouched. Part 3 — updated PageAuthorizationGuardTests census: removed the 10 deleted ConfigEditor pages + ClusterDrivers, updated group-count comments (ConfigEditor 21->11, AuthenticatedRead 17->16). Removed the now-dead Clusters.Drivers usings from the 4 *DriverPageFormSerializationTests + the guard test. Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox