Skip to content

U4: formbridge — headless MCP without Qt; the generic UI bridge leaves OpenHCS - #1206

Merged
trissim merged 13 commits into
mainfrom
refactor/U4-formbridge
Oct 12, 2026
Merged

trissim merged 13 commits into
mainfrom
refactor/U4-formbridge

Conversation

@trissim

@trissim trissim commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Surface U4 (receipt). Merged with main at 44980dfe2 (E1, K2, K3, N1). Against the published MCP snapshot only openhcs_ui_get_state_surface differs (required surface_id); the receipt lists every deliberate contract change.

Libraries (not tagged; owner releases in this order, then repins OpenHCS):

  1. formbridge 0.1.0 — 0.1.0: the toolkit-neutral tier of pyqt-reactive and the running-UI bridge formbridge#1 (external/formbridge points at its branch head)
  2. pyqt-reactive 0.6.0 — 0.6.0: depend on formbridge; keep only Qt code; Qt half of the UI bridge PyQT-reactive#23 (external/pyqt-reactive points at its branch head; remove its requirements-ci.txt formbridge line once 0.1.0 is on PyPI)
  3. OpenHCS: this PR, bounds formbridge>=0.1,<0.2 and pyqt-reactive>=0.6,<0.7

What changes

  • Headless MCP never imports PyQt6: mcp/execution.py serves main-thread calls through formbridge's QueuedMainThreadDispatcher instead of a QCoreApplication event loop, and the Qt-free tier of pyqt-reactive (10.8k lines) moved to formbridge. The two B5 cold-build tests pass.
  • The generic UI bridge (DTOs, operation family, client, descriptors, transport, server, registry, in-process bridge, ObjectState projections) moved to formbridge; window introspection and the ObjectState code-document window providers to pyqt-reactive. OpenHCS declares OpenHCSUiBridgeApplication (protocol openhcs.ui_bridge.v4), its identities, surfaces, and the selected-dataset workflow and session-events operations.
  • Bridge widget id datasets (was plate_manager); openhcs_ui_get_state_surface requires surface_id (MCP contract fixture updated for exactly these two tool records).
  • Identity enums, UiBridgeDescriptorEnvironment, the protocol constants and the dev client's WorkflowTerminalStateCriterion deleted (derived from identities, the application declaration and DatasetWorkflowOperation). DualEditorWindow._current_function_spec and openhcs/utils/performance_monitor.py deleted (unused).
  • QApplication teardown: 0 crashes in 18 runs here and 8 on the E1 head; the smoke test exits normally again.

Guards: tests/unit/test_formbridge_guards.py (MCP stdio+hosted and every formbridge module load no PyQt6/PyQt5/PySide/qtpy; OpenHCS defines no class the libraries own; the libraries import no openhcs; deleted names stay deleted; moved modules are gone), formbridge test_no_toolkit_imports.py, pyqt-reactive test_only_qt_code.py. Structural ratchet (openhcs, scripts, benchmark) and NRA R1 against c7a953030: no increase.

U4 · PR #1206 · guards 5/5 · production −13730 +736 · tests −527 +585

🤖 Generated with Claude Code

trissim and others added 7 commits October 11, 2026 13:09
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…idge

mcp/execution.py serves main-thread calls through formbridge's
QueuedMainThreadDispatcher instead of a QCoreApplication event loop, and
every OpenHCS import of a module that moved from pyqt-reactive to
formbridge names its new home. The stdio and hosted MCP servers now build
without loading PyQt6 (the two B5 cold-build tests pass).

DualEditorWindow._current_function_spec and the
DualEditorSession.current_function_spec it forwarded to had no caller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…HCS declares its application

The UI-bridge DTOs, operation family, client service, descriptor discovery,
transport, server, provider registry, in-process bridge and ObjectState
projections move to formbridge (Qt-free); window introspection and the
ObjectState code-document window providers move to pyqt-reactive. OpenHCS
keeps its declarations: OpenHCSUiBridgeApplication (protocol v4, endpoint,
transport, environment names), its identities, the dataset, pipeline-editor,
debug and live-measurement surfaces, the selected-dataset workflow and
session-events operations (OpenHCSUiAgentBridgeService), and the MCP
capabilities.

- The identity enums (UiCodeDocumentId, UiStateSurfaceId, UiWidgetId) restated
  the identity registry and are deleted; window aliases are declared on the
  identity classes and the dataset-list scope is a HiddenObjectStateScope.
- The bridge widget id is datasets (was plate_manager), with
  datasets.orchestrator_config, datasets.state and datasets.live_measurements.
- The dev client's WorkflowTerminalStateCriterion restated the dataset workflow
  operations; the terminal and failed row states now live on them.
- OpenHCSMainWindow is a UiBridgeHostWindow; PyQtServiceAdapter is a
  UiHostServices (the colour-scheme protocol pyqt-reactive reads).
- The unused copy openhcs/utils/performance_monitor.py is deleted.
- The offscreen smoke test exits normally again: QApplication teardown no
  longer crashes (0 of 18 runs here, 0 of 8 on the E1 head).
- Guards: tests/unit/test_formbridge_guards.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cates

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e branch heads

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 11, 2026 19:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

trissim and others added 6 commits October 11, 2026 15:42
…n only by the required surface_id

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…asset follows the datasets id

The headless guard imports openhcs first so its subprocess resolves formbridge
through the source-checkout activation. Config-consumer and mirror-deletion
scans, U3's generic-Qt guards, the help-projection scan and the desktop update
worker's source path include external/formbridge. README, docs validation and
the docs workflow list it. website/assets/gallery/ui-plate-manager.webp and its
two records are renamed to ui-datasets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The installed-GUI smoke keeps formbridge's bridge DTO paths and the
datasets widget identity, and reads the action status as the
UiActionInvocationStatus class family from formbridge.bridge.dto.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
formbridge 0.1.0 and pyqt-reactive 0.6.0 replace the branch heads;
ObjectState 2.1.1, PolyStore 0.6.1 and zmqruntime 0.6.2 become the
dependency floors, with the submodules at those tags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trissim
trissim merged commit 475f71b into main Oct 12, 2026
1 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants