qt: promote FormsControllerCore into a generic, Sharing-aware model bridge core - #828
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…ridge core Every example rung's *_qml_bridge pair hand-rolls the same schema-driven dispatch wiring (morph#793). The shipped FormsControllerCore<Model> already solved this generically, but examples/pastebin predates its composing constructor and still carried a near-byte-for-byte duplicate, PasteFormsController, whose own doc comment already flagged the gap as closed but unadopted. Extract the model-agnostic core into morph::qt::bridge::GenericModelBridgeCore <Model, Sharing>, promoting the sharing policy (previously hardcoded to NoSharing) to an explicit template parameter and naming its one dispatch operation `execute` after the call it forwards to (BridgeHandler::executeJson), rather than a form-specific verb. The core deliberately does not carry a schemasJson document itself -- that is a forms-rendering concept nothing in execute() reads. FormsControllerCore<Model, Sharing> becomes a thin facade over the core, composing it (not inheriting -- neither type declares a virtual destructor) and forwarding Sharing unchanged, adding only the schemasJson document DynamicForm.qml needs and naming the dispatch operation submitIfValid/ fetchOptions. DynamicForm.qml and every existing FormsController wrapper are source-compatible and unaffected. Retrofit examples/pastebin's FormsBridge to compose FormsControllerCore <PasteModel> directly, deleting PasteFormsController. PasteBridge (the read/query half) is untouched -- its DTO-to-QVariantMap field curation and display formatting is genuinely per-model, not part of this seam. Register the new header in morph_qt_forms's FILE_SET HEADERS so it installs with the qt_forms component alongside forms_controller_core.hpp, which includes it. clang-tidy-diff: pass -Wno-pragma-once-outside-header, same fix already landed on build/core-cpp (45daa1c, unmerged): a brand-new header is pinned and analysed as its own main file, so its #pragma once is reported against it. Also tighten a pre-existing pastebin lambda's by-value std::string parameter (only read, never moved) to const std::string& -- flagged because this diff's re-indentation put that line in the analysed range for the first time. Towards morph#793 (does not close it: the issue's own close condition is a new rung written in materially fewer lines, which this does not attempt). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
Yaraslaut
force-pushed
the
feature/793-generic-model-bridge-core
branch
from
September 26, 2026 07:11
febf85c to
9e8b109
Compare
Yaraslaut
added a commit
that referenced
this pull request
Sep 26, 2026
…ollerCore BookmarkFormsController hand-rolled exactly what morph::qt::forms:: MultiModelFormsControllerCore (previous commit) now provides generically: one BridgeHandler per model (AuthModel, BookmarkModel, TagModel) and an actionType -> handler routing table, plus a try/catch converting the routing throw into the same onError shape every other failure takes. Delete BookmarkFormsController entirely. FormsBridge now composes MultiModelFormsControllerCore<NoSharing, AuthModel, BookmarkModel, TagModel> directly, over the Bridge&/IExecutor* AppContext::onReady() hands it -- same pattern examples/pastebin's FormsBridge already uses for FormsControllerCore<PasteModel> (#828). The rung's existing suite (test_bookmark_qml_bridges.cpp) already covered all six actions' routing and the unrouted-action error message end-to-end through FormsBridge, so it proves the auto-derived routing reproduces the hand-written table's behaviour unchanged -- verified: same 837 assertions across 130 test cases pass unmodified, including the six-action routing case and the CreateBookmarks/ListSharedFeed unrouted-action case. Update every other place that named BookmarkFormsController by symbol (bookmark_schemas.hpp, main_wasm.cpp, polls' and kanban's own doc comments comparing their shape to it, the DynamicForm choiceless-controller test) to point at FormsBridge/MultiModelFormsControllerCore instead, so no comment is left describing a class that no longer exists. Kanban's ProjectAdminPresenter comment is updated to explain, rather than merely note, why its own routing stays hand-written: its per-action side effects (re-decoding CreateProject's body for a typed signal, installing a session on Login, redacting a token) are tangled into the routing in a way MultiModelBridgeCore's generic dispatch cannot serve without also templating those effects -- confirmed by reading ProjectAdminPresenter::submitForm and BookmarkFormsController:: dispatch side by side, per the triage's own named contingency for this case. Closes #827 Claude-Session: https://claude.ai/code/session_018fEUahMFF32wQLiWjbsfkc Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
Yaraslaut
added a commit
that referenced
this pull request
Sep 26, 2026
…ollerCore BookmarkFormsController hand-rolled exactly what morph::qt::forms:: MultiModelFormsControllerCore (previous commit) now provides generically: one BridgeHandler per model (AuthModel, BookmarkModel, TagModel) and an actionType -> handler routing table, plus a try/catch converting the routing throw into the same onError shape every other failure takes. Delete BookmarkFormsController entirely. FormsBridge now composes MultiModelFormsControllerCore<NoSharing, AuthModel, BookmarkModel, TagModel> directly, over the Bridge&/IExecutor* AppContext::onReady() hands it -- same pattern examples/pastebin's FormsBridge already uses for FormsControllerCore<PasteModel> (#828). The rung's existing suite (test_bookmark_qml_bridges.cpp) already covered all six actions' routing and the unrouted-action error message end-to-end through FormsBridge, so it proves the auto-derived routing reproduces the hand-written table's behaviour unchanged -- verified: same 837 assertions across 130 test cases pass unmodified, including the six-action routing case and the CreateBookmarks/ListSharedFeed unrouted-action case. Update every other place that named BookmarkFormsController by symbol (bookmark_schemas.hpp, main_wasm.cpp, polls' and kanban's own doc comments comparing their shape to it, the DynamicForm choiceless-controller test) to point at FormsBridge/MultiModelFormsControllerCore instead, so no comment is left describing a class that no longer exists. Kanban's ProjectAdminPresenter comment is updated to explain, rather than merely note, why its own routing stays hand-written: its per-action side effects (re-decoding CreateProject's body for a typed signal, installing a session on Login, redacting a token) are tangled into the routing in a way MultiModelBridgeCore's generic dispatch cannot serve without also templating those effects -- confirmed by reading ProjectAdminPresenter::submitForm and BookmarkFormsController:: dispatch side by side, per the triage's own named contingency for this case. Closes #827 Claude-Session: https://claude.ai/code/session_018fEUahMFF32wQLiWjbsfkc Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
Yaraslaut
added a commit
that referenced
this pull request
Sep 26, 2026
…ollerCore BookmarkFormsController hand-rolled exactly what morph::qt::forms:: MultiModelFormsControllerCore (previous commit) now provides generically: one BridgeHandler per model (AuthModel, BookmarkModel, TagModel) and an actionType -> handler routing table, plus a try/catch converting the routing throw into the same onError shape every other failure takes. Delete BookmarkFormsController entirely. FormsBridge now composes MultiModelFormsControllerCore<NoSharing, AuthModel, BookmarkModel, TagModel> directly, over the Bridge&/IExecutor* AppContext::onReady() hands it -- same pattern examples/pastebin's FormsBridge already uses for FormsControllerCore<PasteModel> (#828). The rung's existing suite (test_bookmark_qml_bridges.cpp) already covered all six actions' routing and the unrouted-action error message end-to-end through FormsBridge, so it proves the auto-derived routing reproduces the hand-written table's behaviour unchanged -- verified: same 837 assertions across 130 test cases pass unmodified, including the six-action routing case and the CreateBookmarks/ListSharedFeed unrouted-action case. Update every other place that named BookmarkFormsController by symbol (bookmark_schemas.hpp, main_wasm.cpp, polls' and kanban's own doc comments comparing their shape to it, the DynamicForm choiceless-controller test) to point at FormsBridge/MultiModelFormsControllerCore instead, so no comment is left describing a class that no longer exists. Kanban's ProjectAdminPresenter comment is updated to explain, rather than merely note, why its own routing stays hand-written: its per-action side effects (re-decoding CreateProject's body for a typed signal, installing a session on Login, redacting a token) are tangled into the routing in a way MultiModelBridgeCore's generic dispatch cannot serve without also templating those effects -- confirmed by reading ProjectAdminPresenter::submitForm and BookmarkFormsController:: dispatch side by side, per the triage's own named contingency for this case. Closes #827 Claude-Session: https://claude.ai/code/session_018fEUahMFF32wQLiWjbsfkc Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
Yaraslaut
added a commit
that referenced
this pull request
Sep 26, 2026
…ollerCore BookmarkFormsController hand-rolled exactly what morph::qt::forms:: MultiModelFormsControllerCore (previous commit) now provides generically: one BridgeHandler per model (AuthModel, BookmarkModel, TagModel) and an actionType -> handler routing table, plus a try/catch converting the routing throw into the same onError shape every other failure takes. Delete BookmarkFormsController entirely. FormsBridge now composes MultiModelFormsControllerCore<NoSharing, AuthModel, BookmarkModel, TagModel> directly, over the Bridge&/IExecutor* AppContext::onReady() hands it -- same pattern examples/pastebin's FormsBridge already uses for FormsControllerCore<PasteModel> (#828). The rung's existing suite (test_bookmark_qml_bridges.cpp) already covered all six actions' routing and the unrouted-action error message end-to-end through FormsBridge, so it proves the auto-derived routing reproduces the hand-written table's behaviour unchanged -- verified: same 837 assertions across 130 test cases pass unmodified, including the six-action routing case and the CreateBookmarks/ListSharedFeed unrouted-action case. Update every other place that named BookmarkFormsController by symbol (bookmark_schemas.hpp, main_wasm.cpp, polls' and kanban's own doc comments comparing their shape to it, the DynamicForm choiceless-controller test) to point at FormsBridge/MultiModelFormsControllerCore instead, so no comment is left describing a class that no longer exists. Kanban's ProjectAdminPresenter comment is updated to explain, rather than merely note, why its own routing stays hand-written: its per-action side effects (re-decoding CreateProject's body for a typed signal, installing a session on Login, redacting a token) are tangled into the routing in a way MultiModelBridgeCore's generic dispatch cannot serve without also templating those effects -- confirmed by reading ProjectAdminPresenter::submitForm and BookmarkFormsController:: dispatch side by side, per the triage's own named contingency for this case. Closes #827 Claude-Session: https://claude.ai/code/session_018fEUahMFF32wQLiWjbsfkc Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
Yaraslaut
added a commit
that referenced
this pull request
Sep 26, 2026
…ollerCore BookmarkFormsController hand-rolled exactly what morph::qt::forms:: MultiModelFormsControllerCore (previous commit) now provides generically: one BridgeHandler per model (AuthModel, BookmarkModel, TagModel) and an actionType -> handler routing table, plus a try/catch converting the routing throw into the same onError shape every other failure takes. Delete BookmarkFormsController entirely. FormsBridge now composes MultiModelFormsControllerCore<NoSharing, AuthModel, BookmarkModel, TagModel> directly, over the Bridge&/IExecutor* AppContext::onReady() hands it -- same pattern examples/pastebin's FormsBridge already uses for FormsControllerCore<PasteModel> (#828). The rung's existing suite (test_bookmark_qml_bridges.cpp) already covered all six actions' routing and the unrouted-action error message end-to-end through FormsBridge, so it proves the auto-derived routing reproduces the hand-written table's behaviour unchanged -- verified: same 837 assertions across 130 test cases pass unmodified, including the six-action routing case and the CreateBookmarks/ListSharedFeed unrouted-action case. Update every other place that named BookmarkFormsController by symbol (bookmark_schemas.hpp, main_wasm.cpp, polls' and kanban's own doc comments comparing their shape to it, the DynamicForm choiceless-controller test) to point at FormsBridge/MultiModelFormsControllerCore instead, so no comment is left describing a class that no longer exists. Kanban's ProjectAdminPresenter comment is updated to explain, rather than merely note, why its own routing stays hand-written: its per-action side effects (re-decoding CreateProject's body for a typed signal, installing a session on Login, redacting a token) are tangled into the routing in a way MultiModelBridgeCore's generic dispatch cannot serve without also templating those effects -- confirmed by reading ProjectAdminPresenter::submitForm and BookmarkFormsController:: dispatch side by side, per the triage's own named contingency for this case. Closes #827 Claude-Session: https://claude.ai/code/session_018fEUahMFF32wQLiWjbsfkc Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
FormsControllerCore<Model>into a newmorph::qt::bridge::GenericModelBridgeCore<Model, Sharing>, promoting the handler's sharing policy from a hardcodedNoSharingto an explicit template parameter, and naming its one dispatch operationexecuteafter the call it forwards to (BridgeHandler::executeJson).FormsControllerCore<Model, Sharing>becomes a thin facade composing the new core (not inheriting — neither type declares a virtual destructor), adding only theschemasJsondocumentDynamicForm.qmlneeds.DynamicForm.qmland every existingFormsControllerwrapper are source-compatible and unaffected.examples/pastebin'sFormsBridgeto composeFormsControllerCore<PasteModel>directly, deleting the now-redundantPasteFormsController(a near-byte-for-byte duplicate whose own doc comment already flagged the gap as closed-but-unadopted).PasteBridge(the read/query half) is untouched.morph_qt_forms'sFILE_SET HEADERSso it installs with theqt_formscomponent.Towards morph#793 (does not close it — the issue's own close condition is a new rung written in materially fewer lines, which this does not attempt). Filed morph#827 as a separate, adjacent finding surfaced while retrofitting pastebin:
examples/bookmarks'sBookmarkFormsControllerhand-rolls multi-model action routing that no core template currently supports — out of scope here.Test plan
ladder_pastebin_gui_libandladder_pastebin_testsbuild cleanladder_pastebin_tests: all 764 assertions / 58 test cases passladder_bookmarks_gui_libbuilds clean (doc-only change there)ctestsuite (macos-ladder, all 7 rungs): 2759/2759 tests pass-DMORPH_BUILD_DOCUMENTATION=ON,WARN_AS_ERROR=FAIL_ON_WARNINGS): clean, no warningscmake --installagainst a-DMORPH_BUILD_QT=ON -DMORPH_BUILD_FORMS_QML=ONconfiguration (this was broken before theCMakeLists.txtfix — caught by review)Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
🤖 Generated with Claude Code