Skip to content

paper: match 0.8.0 - #31

Open
trissim wants to merge 1 commit into
mainfrom
paper/match-0.8.0
Open

trissim wants to merge 1 commit into
mainfrom
paper/match-0.8.0

Conversation

@trissim

@trissim trissim commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Brings paper.md in line with the code at v0.8.0 (1c0f35f, which is also main). No library code changes. Paths below are under src/pyqt_reactive/ unless prefixed; formbridge: means formbridge v0.1.4 and objectstate: means ObjectState v4.0.0, the versions 0.8.0 requires, read through the GitHub API.

Nothing was executed: this is a PyQt library and no environment was created. Every name, import path and call signature in the two code examples was checked by reading the source (ParameterFormManager.__init__(state, config) forms/parameter_form_manager.py:314, FormManagerConfig :74, ColorScheme theming/init.py:9, ObjectState.__init__(object_instance, scope_id, ...) objectstate:object_state.py:145, set_base_config_type objectstate:init.py:120; AbstractManagerWidget class attributes widgets/shared/abstract_manager_widget.py:586-613, _action_handlers :267, ManagerStateBinding formbridge:managers/state_binding.py:8, ManagerItemHooks and AttributeItemIdProjection formbridge:managers/item_hooks.py:33,46, ListItemFormat widgets/shared/manager_item_display_builder.py:33). The first example is the repository's own docs/quickstart.md. The examples were not run. The second is a class fragment: it omits the seven abstract methods the text lists, so it cannot be instantiated as printed.

Claim ledger

# Old claim Status What it became Source
1 The library is called pyqt-reactor (title, the text throughout, and two bib notes) false pyqt-reactive everywhere pyproject.toml:6
2 Summary example: four class attributes on AbstractManagerWidget are the whole declaration false New example with the real attribute types; see 3 to 6 widgets/shared/abstract_manager_widget.py:586-613
3 BUTTON_CONFIGS = [("Add", "add_step"), ...] (2-tuples naming methods) false 3-tuples (label, action_id, tooltip); handlers come from _action_handlers(). The string tables ACTION_REGISTRY / DYNAMIC_ACTIONS raise NotImplementedError button_panel.py:65; abstract_manager_widget.py:231-235, 267
4 ITEM_HOOKS = {'backing_attr': 'steps', 'selection_signal': 'step_selected'} false ITEM_HOOKS must be a ManagerItemHooks (a dict raises TypeError); backing list and selection are named by a required STATE_BINDING widgets/shared/manager_item_access.py:31-39
5 PREVIEW_FIELD_CONFIGS = [...] configures row previews false Removed. The name occurs only in three docstrings; nothing reads it. Row fields are LIST_ITEM_FORMAT abstract_manager_widget.py:574, 581, 660 (only hits)
6 "implements three methods: add_step(), del_step(), edit_step(). The base class handles everything else" false Seven abstract methods, listed by name abstract_manager_widget.py:759, 769, 794, 806, 819, 887, 892
7 Declaration "inherits complete CRUD infrastructure, cross-window reactivity, flash animations, dirty tracking, undo/redo, and live preview formatting" partly Lists what the base class does: reorderable list, button panel, selection, delete and edit actions, code-editor action, row refresh, row flashes, refresh after time travel. "Dirty tracking" and "undo/redo" are ObjectState's, not the manager's abstract_manager_widget.py:123-143, 279-289, 430-444, 730
8 "selection with dirty-check prevention, drag-and-drop with undo" unverifiable Removed. The code prevents deselection; I found no undo record for a reorder in this repository abstract_manager_widget.py:359-363, 412-417
9 LIST_ITEM_FORMAT: "Multiline display with formatters" true Kept in the example as a ListItemFormat manager_item_display_builder.py:33-40
10 "FieldChangeDispatcher routes changes with reentrancy guards" true Kept, with the stages it runs services/field_change_dispatcher.py:48-87, 378-411
11 "ObjectStateRegistry notifies listeners via contextvars isolation" false as worded "notifies the listeners of ObjectStateRegistry". contextvars does not occur in this package field_change_dispatcher.py:290-294; grep -rw contextvars src is empty
12 "CrossWindowPreviewMixin debounces updates to prevent storms during rapid typing" misleading The mixin has a 20 ms debounce, but AbstractManagerWidget, its only user in the package, overrides the hook and does not use it. The paper now says list managers listen on the registry and refresh their rows widgets/mixins/cross_window_preview_mixin.py:38, 120-135; abstract_manager_widget.py:207-209
13 "Windows refresh only affected fields based on type-hierarchy matching" true in effect, wrong mechanism Each root form subscribes to its own state's on_resolved_changed; ObjectState supplies the changed paths; the form refreshes and flashes those forms/parameter_form_manager.py:584, 1070-1127; objectstate:object_state.py:572
14 Pipeline/Step num_workers example true as a description of the mechanism Kept, shortened services/widget_service.py:311-328
15 "This is what React does for web components" unverifiable comparison One sentence on what is taken from React: a view is derived from state
16 Table: React has cross-window sync and hierarchical config; "JavaScript cannot introspect types at runtime the way Python can" unverifiable, and not about this software React column, footnote and sentence removed
17 Table row "O(1) animations" false as worded Row removed. The coordinator's own docstring says O(k) per tick in flashing elements. Design text says work grows with flashing elements animation/flash_mixin.py:2370-2374
18 magicgui "stops there" (presented only as an alternative) misleading The paper now says pyqt-reactive calls magicgui for leaf widgets it has no widget of its own for forms/widget_strategies.py:14-15, 515, 721, 758-800; pyproject.toml dependencies
19 Table cells for Qt Designer, magicgui, Streamlit not checked against those tools Kept as the author's statements, "—"/"✓" written as no/yes
20 "Forms integrate with ObjectState for dual-axis inheritance" through context and class hierarchy true, and it is ObjectState's Says so: "Inheritance is ObjectState's ... pyqt-reactive displays it" objectstate:dual_axis_resolver.py; services/widget_service.py:321
21 "None means inherit. Placeholder text shows the inherited value" true Kept, naming the one read state.get_resolved_value(path) services/widget_service.py:311-328
22 "no synchronization bugs, no hidden state" unverifiable Removed
23 "CodegenProviderABC and ... PreviewFormatterRegistry" as this package's integration points false since 0.6.0 Both are in formbridge; the paper says so and names the abstract classes that are in this package formbridge:protocols/codegen_provider.py:9, preview_formatter.py:11; windows/config_window.py:86; windows/tabbed_editor_window.py:48, 105
24 "The framework knows nothing about the host application's domain" true for imports only "The package does not import its host application" no import openhcs in src; 31 mentions of OpenHCS in docstrings and one attribute name (utils/window_utils.py:86)
25 "GlobalFlashCoordinator runs a single timer, pre-computes all interpolated colors" true, wrong name The class is private (_GlobalFlashCoordinator); the paper describes it without naming it animation/flash_mixin.py:2367, 2499-2501
26 "WindowFlashOverlay renders every flash rectangle in one paintEvent" true (per window) Kept, "one transparent widget per top-level window" animation/flash_mixin.py:1219-1229, 2184
27 "naive implementations scale O(n) ... unacceptable"; "Game-engine solution" unverifiable Removed; frame-rate default stated instead (screen rate capped at 60) animation/flash_config.py:135, 142-161
28 "Forms generate from any callable: functions, dataclasses, classes (via __init__), or objects with __call__ ... Pass a function, get a form" misleading A form is built from an ObjectState, not from a callable. The analysis is one call to UnifiedParameterAnalyzer.analyze; which kinds of object that accepts is python-introspect's claim and is not restated forms/parameter_form_manager.py:284-286, 314, 454-457
29 "ParameterInfo subclasses define matches() predicates; the factory selects the first match" true, in formbridge Kept with the four class names and where they live formbridge:forms/parameter_info_types.py:166-298, 343-345
30 "Services dispatch by class name (_reset_OptionalDataclassInfo)" true Kept; a missing handler raises ValueError services/parameter_ops_service.py:75-77, 110; formbridge:services/parameter_service_abc.py:146-180
31 "No dispatch tables. Exhaustive handling. Type-safe throughout." partly "There is no hand-written dispatch table" (the classes register themselves in a list on definition). The other two are removed: a missing handler is a runtime ValueError, not a static check formbridge:forms/parameter_info_types.py:136-159
32 OpenHCS: multiple synchronized windows, nested hierarchies, scopes, inherited value preview true in OpenHCS today Names the OpenHCS classes that use the library openhcs/pyqt_gui/widgets/pipeline_editor.py:219, plate_manager.py:112, step_parameter_editor.py:226, main.py:861-876
33 "Git-style undo/redo with branching timelines" unverifiable here (ObjectState's) "a time-travel widget over ObjectState history" widgets/time_travel.py:34-63
34 "Responsive updates across all windows during active editing. No perceptible lag." unverifiable (no measurement) Removed
35 "Function editors generate forms from any callable signature" not re-verified in OpenHCS Removed
36 "These are the same patterns. pyqt-reactor provides them once." and "eliminates this work" marketing Removed

False or misleading: 13 (rows 1, 2, 3, 4, 5, 6, 11, 12, 17, 18, 23, 28, and 31 in part). Removed as unverifiable: 8 (rows 8, 15, 16, 22, 27, 33 reworded, 34, 35).

The paper had no line counts, widget counts, "N% less code" figures, frame-rate or latency numbers. The one number now in it (60 frames per second) is a default in the source, not a measurement.

New statements, with their source

  • Forms hold widgets, the state holds values: ParameterFormManager.__init__ takes an ObjectState (forms/parameter_form_manager.py:314-327).
  • The Qt-free tier is in formbridge (CHANGELOG 0.6.0; imports at abstract_manager_widget.py:21-80; pyproject.toml dependencies).
  • Dispatch stages in order (services/field_change_dispatcher.py:399-403); sibling refresh by field name (:182-207).
  • Config window keeps no copy of the global config; save is mark_saved() per tab inside ObjectStateRegistry.atomic_success, with checkpoint restore and participant rollback on failure (windows/config_window.py:699-767; CHANGELOG 0.8.0; the 0.7.2 to 0.8.0 diff of that file is +13 -148).
  • ParameterFormManager.owns_field_path answers from the form's displayed fields (forms/parameter_form_manager.py:1456-1470).
  • sole_owner raises NavigationTargetClaimedTwiceError (services/window_navigation.py:61-81), used by CompositeWindowNavigationDriver (:226, :237) and ConfigWindow (windows/config_window.py:329-337).
  • Provenance navigation reads state.get_provenance(path) (widgets/shared/clickable_help_components.py:511; CHANGELOG 0.7.1).
  • UiHostServices is required by every manager (abstract_manager_widget.py:645, 676-677; formbridge:services/host_services.py:11).
  • "The repository contains no timing measurements of this path": scripts/benchmark_form_construction.py measures form construction only and commits no results.

For the owner

  • The paper named the wrong package throughout ("pyqt-reactor"). I changed the title because it stated something false.
  • ParameterFormManager._on_live_context_changed is never connected. dispose disconnects it from ObjectStateRegistry (forms/parameter_form_manager.py:1039) but no line in src connects it; SignalService.register_cross_window_signals only logs (services/signal_service.py:135-148). So the 20 ms placeholder refresh at :992-1026 looks unreachable from inside this package, and the form's cross-window path is state.on_resolved_changed alone. The paper describes only that path.
  • CrossWindowPreviewMixin's debounce is bypassed by its only subclass in the package (row 12), and PREVIEW_FIELD_CONFIGS exists only in docstrings (row 5). The class docstring at abstract_manager_widget.py:573-575 still tells subclasses to define PREVIEW_FIELD_CONFIGS and ACTION_REGISTRY, and the second now raises.
  • A config tab does not answer ownership from shown fields. _ConfigEditorTab.owns_field_path answers from state.parameters because it is asked before its form is built (windows/config_window.py:235-245). The paper's sentence about shown fields is scoped to ParameterFormManager.
  • OpenHCS pins pyqt-reactive>=0.7.2,<0.8 (pyproject.toml:113 on the OpenHCS branch I read), so Research Application describes OpenHCS on 0.7.x while the paper describes 0.8.0.
  • Not verified: the table cells about Qt Designer, magicgui and Streamlit; which kinds of object UnifiedParameterAnalyzer.analyze accepts; the AI disclosure's model name; the front-matter date (13 January 2026), left as it was.
  • I added one section heading, "One Owner per Field", for the ownership and config-window changes. Everything else keeps the original headings.
  • paper.bib: added formbridge (https://github.com/OpenHCSDev/formbridge, confirmed to exist; author and description taken from its pyproject.toml), please check the entry. pyqt6 is now cited. "pyqt-reactor" corrected in two note fields. The objectstate and pythonintrospect URLs point at github.com/trissim/...; both resolve, and the OpenHCSDev repositories also exist, so I left them for you to choose. Five entries remain uncited (pydantic, gamma1994design, qt6, dataclasses, typehints); none is dangling.
  • Length: 1292 words by wc -w (front matter and code included) against 1144 before, 13% over. The two code examples with their imports account for the difference.

🤖 Generated with Claude Code

Bring paper.md in line with the code at v0.8.0: the library name, the
AbstractManagerWidget declaration, the cross-window mechanism, field
ownership and the config window save. Add the formbridge reference.

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

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.

This branch has not been deployed

No deployments
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