← Back to Updates
July 8th 2026Release

Control Seat V0.2.0

V0.2.0 marks the first production-hardening release since OpenBridge went GA. Nothing in the block palette or UI changes; the release is about three specific bugs that could bite production tenants — one of which could quietly stop all historian writes on tenants that route some tags through an external historian provider. All three are fixed and covered by tests.

What's in V0.2.0

Historian writer no longer wedges on a silent provider

The single most important fix in this release. The historian writer runs its flushes sequentially on one goroutine with no deadline. If an external historian provider (TimescaleDB, another Control Seat historian, any provider on the other side of a NAT path or a paused cloud instance) leaves the TCP connection silent mid-InsertBatch — no error, no data, just nothing — the writer would park on that call forever and silently stop every subsequent flush, including for local tags routed to ClickHouse.

The fix bounds each provider InsertBatch call under a 30-second timeout in the federated router. A hung provider fails its own flush and enters the existing per-provider backoff; the writer moves on and every other tag keeps flowing. Non-hung stores (including the built-in ClickHouse historian) are unaffected: a bounded context only cancels on real timeout, and the read/query paths already have their own contexts.

Test coverage: TestRouterBoundsHangingProviderWrites exercises a provider that blocks its InsertBatch until context cancellation, verifies the batch returns as historian.BatchError with only the hung provider's points in Failed, and confirms the default store's points still made it through.

You'll notice this: cloud tenants using external historian providers see zero unexplained silent-history-loss events after upgrading. On-prem tenants that pull writes through a slow external historian never see the driver-host go zombie again.

Dock resizer drag no longer freezes over embedded content

Dashboards that host embedded views inside docks (a very common layout — sidebar dock with an embedded page inside it) had a resize bug: as soon as the cursor entered the iframe during a drag, the iframe swallowed the mouse events and the resize froze mid-gesture until you released and re-clicked outside the iframe.

Rewrote the dock resizer to use pointer events with setPointerCapture on the resizer strip itself. Once the drag starts, pointer moves are routed to the strip regardless of what's under the cursor. A body.cs-dock-resizing class disables pointer-events on iframes as a fallback and pins user-select: none so text doesn't get selected during a fast drag. The dock open/close CSS transition (which was making the handle ease 250ms late during a drag) is also disabled during the gesture, so the drag now tracks 1:1.

Dock traits no longer knock docks out of position

Editing any dock trait (position, size, background, etc.) used to visibly shift the dock out of its docked position until the page refreshed. Every trait edit funneled through GrapesJS's syncDockAttrs → addAttributes path, which reacts to change:attributes by clearing every DOM attribute before re-applying the model's attribute set. That wipe removed the imperative styles that applyDockPosition had set on the dock element, so the dock fell out of its fixed position.

The dockView now listens for change:attributes explicitly and re-runs updateDockLayout() + updateDockContent() after the wipe, restoring the imperative styles.

Dev-only improvements

Two additions worth mentioning for anyone contributing to the codebase locally, both mounted only in dev mode:

  • /debug/pprof/* endpoints on driverhost — the only way to diagnose an in-process wedge like the historian writer bug above without killing the process. Never mounted on the production listener; pprof endpoints leak internals and are gated by isDev at route registration time.
  • scripts/dev.sh improvements — the ClickHouse users override file at /private/tmp/ch-users-override.xml now gets regenerated whenever its contents don't match the running CS_CH_PASSWORD (macOS wipes /tmp periodically); XML special chars in the password are escaped so exotic characters can't corrupt the config; cs-postgres and cs-clickhouse containers auto-start if they're stopped but exist; and a fakepi process launches on :8765 for the 100k federated PI tag dev workload.

Migration notes

  • No CDK, Postgres, or ClickHouse migrations in this release. Deploy-only rollout.
  • No config surface changes. The 30-second write timeout is a fixed constant in the router; test-only override on FederatedBackend.writeTimeout.
  • No new dependencies.

That's V0.2.0. Small in scope; the historian fix is the reason to upgrade.