You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Foundational work for integrating external infrastructure devices into Proto Fleet: facility-side equipment (fans, and later PDUs, dampers, pumps, ...) that the server can inventory and eventually command, with all protocol knowledge isolated behind a driver adapter registry so the core stays protocol-agnostic. Facility fans (single fan or fan group behind a PLC/drive) are the first device kind, and Modbus TCP is the first driver adapter — motivated by curtailment sequencing (fans off after a delay once miners are curtailed; fans on first, then miners restored after a delay), but the foundation is deliberately kind- and protocol-agnostic.
No device behavior activates from this work — the write path lands with the later Modbus I/O and reconciler-sequencing phases. This is inert surface area until then.
Delivered by #724. Full design: docs/plans/2026-07-09-facility-fan-curtailment-integration-plan.md (see "Delivery: PR grouping").
proto/infrastructure/v1/infrastructure.proto: InfrastructureDevice (opaque driver_config, no per-protocol messages; device_kind/driver_type as strings so new kinds and protocols are never wire breaks) + InfrastructureService List/Get/Create/Update/Delete; just gen, generated code committed together
driver/modbustcp/ config parsing + ValidateConfig: unit ID 1–247, port 1–65535, register address 0–65535, endpoint restricted to private/loopback/link-local (mirrors the MQTT subscriber's validateBrokerTransport guard). Protocol I/O is a later phase, not here
Domain CRUD service: protocol-blind field validation in core, driver_config validation delegated to the registry; transactional writes with a site row-lock (TOCTOU guard vs concurrent DeleteSite)
DeleteSite cascade soft-deletes the site's infrastructure devices
Connect handlers gated on site:read / site:manage
Tests: Postgres integration (CRUD, validation matrix, org isolation, site cascade), driver/adapter unit tests incl. adversarial endpoint vectors, handler auth-gate and translation tests
Out of scope (later phases of the fan integration)
Client add/edit/persist UI
Response-profile fan settings (facility_fan_device_ids, delays) + the device deletion reference-guard that depends on that column
Modbus TCP write path + dev simulator
Reconciler fan sequencing (delays, per-cycle re-assertion, terminal-path handling)
Extensibility notes (for future device kinds like PDUs)
New protocol (SNMP, HTTP, BACnet, ...): one adapter package + one registry line + a client form module — no schema/proto/handler changes.
New device kind (e.g. PDU): a migration extending the kind CHECK constraints plus additive edits to the proto validation list and models.ValidKind; sub-component control (PDU outlets) fits by modeling each outlet as its own device row.
New capability (e.g. fan speed): additive DesiredState fields, gated per-driver via Capabilities().
Repo hygiene
just gen after proto/sqlc/migration changes; feature branch (never main); just lint before PR.
Summary
Foundational work for integrating external infrastructure devices into Proto Fleet: facility-side equipment (fans, and later PDUs, dampers, pumps, ...) that the server can inventory and eventually command, with all protocol knowledge isolated behind a driver adapter registry so the core stays protocol-agnostic. Facility fans (single fan or fan group behind a PLC/drive) are the first device kind, and Modbus TCP is the first driver adapter — motivated by curtailment sequencing (fans off after a delay once miners are curtailed; fans on first, then miners restored after a delay), but the foundation is deliberately kind- and protocol-agnostic.
No device behavior activates from this work — the write path lands with the later Modbus I/O and reconciler-sequencing phases. This is inert surface area until then.
Delivered by #724. Full design:
docs/plans/2026-07-09-facility-fan-curtailment-integration-plan.md(see "Delivery: PR grouping").Scope
infrastructure_devicetable —site_idFK,building_name,name,device_kind(single_fan|fan_group),fan_count,enabled,driver_type(text),driver_config(opaque jsonb owned by the adapter), timestampsproto/infrastructure/v1/infrastructure.proto:InfrastructureDevice(opaquedriver_config, no per-protocol messages;device_kind/driver_typeas strings so new kinds and protocols are never wire breaks) +InfrastructureServiceList/Get/Create/Update/Delete;just gen, generated code committed togetherserver/internal/domain/infrastructure/driver/—Controllerinterface (SetState(ctx, device, DesiredState),ValidateConfig,Capabilities(); doc comment reservingReadStatusfor v2 read-back) anddriver_type→ adapter factory registrydriver/modbustcp/config parsing +ValidateConfig: unit ID 1–247, port 1–65535, register address 0–65535, endpoint restricted to private/loopback/link-local (mirrors the MQTT subscriber'svalidateBrokerTransportguard). Protocol I/O is a later phase, not hereserver/sqlc/queries/infrastructure_device.sql), org-scopeddriver_configvalidation delegated to the registry; transactional writes with a site row-lock (TOCTOU guard vs concurrentDeleteSite)DeleteSitecascade soft-deletes the site's infrastructure devicessite:read/site:manageOut of scope (later phases of the fan integration)
facility_fan_device_ids, delays) + the device deletion reference-guard that depends on that columnExtensibility notes (for future device kinds like PDUs)
models.ValidKind; sub-component control (PDU outlets) fits by modeling each outlet as its own device row.DesiredStatefields, gated per-driver viaCapabilities().Repo hygiene
just genafter proto/sqlc/migration changes; feature branch (nevermain);just lintbefore PR.