Repository navigation
Conversation
PropertyTable.SetProperty with the broadcast flag queues a Mediator "OnPropertyChanged" job for every changed value, even when no registered colleague has a branch for that name. An inventory of every production SetProperty/SetDefault site against every OnPropertyChanged handler found 113 such sites: dialog geometry, persisted column lists and widths, clerk bookkeeping (RecordClerk-<id>, <id>-Index, filter and sorter ids), startup singletons (window, cache, App, HelpTopicProvider) and the like. Those sites now pass false for the broadcast flag. The value, settings group and persistence calls are unchanged, so the stored state is the same; only the pointless queued job goes away. This is groundwork for moving the remaining OnPropertyChanged traffic to Pub/Sub: the 63 sites that do reach a handler are untouched, as are the XML-driven families (Choice.OnClick, ChoiceGroup, xWindow.LoadDefaultProperties and LinkListener.FollowActiveLink), whose members are decided one by one. Two sites are dead by context rather than by name. InfoPane sets ActiveClerk in the Texts & Words tools, where the only ActiveClerk handler, ReversalClerk, is never a message target. XmlDocConfigureDlg sets the layout property it was opened for, which can only be NotebookPublicationLayout (the Notebook Document tool) or null (the segment preview in Find Example Sentences has no layoutProperty), and neither name has a handler. RecordClerk.ResetStatusBarPanel keeps its broadcast: three of its four callers reach xWindow's status panels. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two OnPropertyChanged overrides wait for property names that no production code ever sets with the broadcast flag. XmlBrowseView reacted to "<browse id>_readOnlyBrowse" by refreshing the selected-row highlighting. Nothing sets such a property, and XmlBrowseViewBase already treats the "_readOnlyBrowse" properties as deprecated, deciding read-only selection from the "editable" attribute. XmlSeqView reacted to "ShowFailingItems-<current tool>" by rebuilding its root box. The only such property is the pane-bar button ShowFailingItems-lexiconClassifiedDictionary, and that tool's view is an XhtmlDocView with its own handler. XmlSeqView is hosted only by XmlDocView in the Notebook Document tool, which has no such button. The field that reads the property once in MakeRoot stays. Both overrides otherwise only called the base handler, so they go entirely, with the two tests that drove the XmlSeqView branch directly and the test helper only they used. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
NUnit Tests 1 files ±0 1 suites ±0 10m 45s ⏱️ - 2m 55s Results for commit 92d6bcf. ± Comparison against base commit bd0608d. This pull request removes 2 tests. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1179 +/- ##
==========================================
- Coverage 39.51% 39.50% -0.01%
==========================================
Files 1537 1537
Lines 354706 354674 -32
Branches 41096 41092 -4
==========================================
- Hits 140160 140131 -29
+ Misses 185154 185153 -1
+ Partials 29392 29390 -2
🚀 New features to boost your workflow:
|
3 of 11 tasks
thejambi
approved these changes
Oct 9, 2026
thejambi
left a comment
Contributor
There was a problem hiding this comment.
@thejambi reviewed 55 files and all commit messages, and made 1 comment.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on mark-sil).
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.
Start here:
Src/Common/Controls/XMLViews/XmlSeqView.cs, the one file where more than a trailing flag changes. The other 52 files each change one trailingtruetofalse.What it does. Every
PropertyTable.SetPropertywith the broadcast flag queues a MediatorOnPropertyChangedjob even when no colleague has a branch for that name. An inventory of all 177 production broadcasting sites against all 23 handlers found 113 whose name nothing handles; those now passfalse. Values, settings groups and persistence calls are untouched. The two handler branches whose names nothing broadcasts are gone too: XmlBrowseView'sreadOnlyBrowsebranch and XmlSeqView'sShowFailingItems-<tool>branch, with the two tests that drove the latter directly; the field that branch updated is now aMakeRootlocal.What breaks? Nothing: every colleague received each dead job and ignored it. The review question is whether the dead set is right; the evidence accordion has the derivation, re-run on current main before editing.
Where to look
ActiveClerk(its value is never the ReversalClerk that handles it) and XmlDocConfigureDlg's layout property (onlyNotebookPublicationLayoutor null is reachable).readOnlyBrowsesetter exists; the onlyShowFailingItems-button belongs to a tool whose view is XhtmlDocView, and XmlSeqView is hosted only by the Notebook Document tool.RecordList.RestoreFromnever restores anything.Not here. The 63 live sites, the four XML-driven family sites (Choice.OnClick, ChoiceGroup, xWindow.LoadDefaultProperties, LinkListener.FollowActiveLink) and RecordClerk.ResetStatusBarPanel keep broadcasting; they convert per workflow later. The inventory lives in the gitignored
Docs/migration/working/folder.Verification. Off main, not stacked.
build.ps1 -CommentHygiene -TokenHygiene: 0 warnings, 0 errors.test.ps1per project: XMLViewsTests 117, xCoreInterfacesTests 19, DetailControlsTests 124 (1 skipped), LexTextDllTests 10, xWorksTests 1777 (2 skipped), all passed. Not run: the full managed suite and the native suites. Nothing a tester can reach changes, so no Jira ticket.Next: approve, or name a flipped site you want argued.
Reading this a year from now -- start here
The inventory behind this PR (every
SetProperty/SetDefaultsite underSrc, everyOnPropertyChangedhandler and the names it reacts to, the 63 live sites classified by reach and timing, the deferral conditions and the workflow index) is a working document in the gitignoredDocs/migration/working/folder:propertytable-broadcast-buckets.md,propertytable-dead-sites.tsvand the extractorpropertytable-broadcast-extract.py. It was never on a branch, so there was nothing to delete here; the parts a reader of this PR needs are summarized in the sections below.Decisions, and why
PropertyTable.BroadcastPropertyChange. A central list of names with no handler would be a second copy of the handler map, and it would rot silently. The flag at the call site is the existing contract, and the next step converts the live sites one workflow at a time, so each site is visited anyway.Choice.OnClick,ChoiceGroupandxWindow.LoadDefaultPropertiesbroadcast whatever name the configuration gives them, andLinkListener.FollowActiveLinksets every property a link carries; their members are decided one by one in the live-site work.RecordClerk.ResetStatusBarPanelkeeps its flag. Three of its four callers reach xWindow's status panels; only theDialogFilterStatuscaller is dead.TemporaryRecordClerk.OnPropertyChangedis an intentional empty override, andTickeris an xCore sample class that production never instantiates.Surprising findings
XmlSeqViewis constructed only byXmlDocView(the Notebook Document tool,XmlDocView.cs:605) and reaches the Mediator throughXmlDocView.GetMessageAdditionalTargets.RecordDocViewhostsXmlDocItemView, notXmlSeqView.RecordDocViewsubclass isRecordDocXmlView, the segment preview inside the modal Find Example Sentences dialog (Lexicon/areaConfiguration.xml). Its parameters carry nolayoutProperty, soRecordDocView.RunConfigureDialogpasses null to the configure dialog (aDebug.Assertfires in debug builds). The Notebook-onlyCmdConfigureXmlDocViewcannot reach it.RecordList.RestoreFromreads the persisted sort sequence, deletes the file and returns false unconditionally, so the persist/restore pair and theFwXWindow.DiscardPropertiespurge are dead weight today. A separate session is looking at it.Src/xWorks/xWorksTests/Avalonia/Hosting/TestLocalizationManagerBootstrap.cs, which is why it reports 178 production broadcasting sites on main against 177 inventoried.Deferred, and what would unblock it
direct: every reacting handler is reachable from the set site;publish: at least one is not) and timing (immediate, ordeferredwith the numbered conditions it fails: set during construction, ordering within the action, handler tears down the sender, re-entry, needs layout or focus settled, thread, teardown, exception ownership, fixed slot among the workflow's other delayed paths). They are grouped by workflow (window initialization, area switch, tool switch, record navigation, clerk activation, follow link, reversal index change, dictionary configuration, writing system and style, view toggles, interlinear tab, UI mode, parser status, respeller apply, filters, Pathway export) and each workflow converts as a unit, coordinated with the JumpToRecord Phase 2, FollowLink and MasterRefresh Phase C plans that share three of them.CheckParserUpdatesAnalyseshas no handler but is set only throughChoice.OnClick; it goes with that family.Evidence
Counts. 427
SetProperty/SetDefaultsites underSrc: 179 in test code, 70 production sites with a literalfalseflag, 177 production broadcasting sites (the extractor reports 178; the extra row is the misclassified test bootstrap file), of which one is excluded because its flag comes from callers that all passfalse(DictionaryConfigurationListener.cs:407), leaving 176 live: 113 dead (this PR) and 63 live (deferred).Inventory versus main. The inventory was taken on a tree at the pre-squash form of #1177. Main has since added #1163, #1177 and #1176; the files that differ are Avalonia detail files and Hermit Crab parser files. None of the 23 handler files, no
GetMessageTargetschain and no file underDistFiles/Language Explorer/Configurationchanged. All 113 dead rows matched main by file, line, member and name before editing.Handlers on main (23), and the names they react to. xWindow/FwXWindow:
currentContentControl,ShowRecordList,WritingSystemHvo,BestStyleName,StatusPanel<id>. AreaListener:currentContentControlObject,areaChoice. NavBarAdapter:areaChoice,ToolForAreaNamed_<current area>. PaneBar: theboolPropertyof its own buttons. MultiPane:ActiveClerkSelectedObject,ToolForAreaNamed_lexicon,Show_<first pane id>. XhtmlDocView:SelectedPublication,DictionaryPublicationLayout,ReversalIndexPublicationLayout,ActiveClerkSelectedObject,ShowFailingItems-lexiconClassifiedDictionary. RecordEditView:ShowHiddenFields-*,UIMode,UIModeDisabledTools. InterlinMaster:InterlinearTab. RecordClerk:ShowRecordList,SelectedTreeBarNode,SelectedListBarNode,currentFilterForRecordClerk_<id>,<providing clerk id>-selected. ReversalClerk:ReversalIndexGuid,ToolForAreaNamed_lexicon,ActiveClerk,ReversalIndexPublicationLayout. TemporaryRecordClerk: nothing. DataTree:ShowHiddenFields,ShowHiddenFields-*,currentContentControlObject. MultiStringSlice, ReversalIndexEntrySlice:SelectedWritingSystemHvosForCurrentContextMenu. BrowseViewer:SortedFromEnd,SortedByLength. XmlBrowseView:<browse id>_readOnlyBrowse(removed here). XmlBrowseRDEView:areaChoiceParameters,currentContentControlParameters. SimpleRootSite:WritingSystemHvo,BestStyleName. XmlSeqView:ShowFailingItems-<current tool>(removed here). RawTextPane:WritingSystemHvo,ActiveClerkSelectedObject,ShowInvisibleSpaces,ClickInvisibleSpace. InterlinDocForAnalysis:ITexts_AddWordsToLexicon. Ticker: everything, never instantiated.Dead-listener derivation. Every handler name above, minus the names broadcast with
trueon main (the 63 live sites and the computed names they produce), minus the XML-driven family members, leaves exactly<browse id>_readOnlyBrowseandShowFailingItems-<current tool>outside the classified-dictionary tool.Computed names at flipped sites, resolved on main.
xWindow.CreateStatusBarsets the raw panel ids (Message,Progress,Area,ProgressBar,Sort,Filter,ParsingDev,RecordNumber), notStatusPanel<id>. The clerk filter and sorter ids come fromRecordList.PropertyTableId(LexDb.Entries_filterand the like), notcurrentFilterForRecordClerk_<id>.PersistedIndexPropertyis<id>-Index;StoreClerkInPropertyTablesetsRecordClerk-<id>. Search-engine names are the Go-dialog engine names; dynamic list keys are the numeric keys in the configuration;PersistenceProvidersets<context>-<id>-<label>.Flipped sites per file (113). Slice.cs 2; BrowseViewer.cs 2; ReallySimpleListChooser.cs 1; SearchEngine.cs 1; XmlBrowseViewBaseVc.cs 2; FieldWorks.cs 2; LexicalProviderImpl.cs 6; MergeObjectDlg.cs 2; LexEntryUi.cs 2; FwFindReplaceDlg.cs 2; ConstituentChart.cs 2; FlexPathwayPlugin.cs 1; ComplexConcControl.cs 1; FilterTextsDialog.cs 1; InfoPane.cs 1; InterlinDocForAnalysis.cs 1; InterlinDocRootSiteBase.cs 1; RawTextPane.cs 1; SandboxBase.designer.cs 1; BaseGoDlg.cs 2; CombineImportDlg.cs 1; NotebookImportWiz.cs 3; LiftImportDlg.cs 2; MasterCategoryListDlg.cs 2; MasterListDlg.cs 2; MsaCreatorDlg.cs 1; MsaInflectionFeatureListDlg.cs 2; PhonologicalFeatureChooserDlg.cs 2; AreaListener.cs 2; FLExBridgeListener.cs 5; ReversalListener.cs 1; SwapLexemeWithAllomorphDlg.cs 1; ConcordanceDlg.cs 2; MorphologyListener.cs 1; RespellerDlg.cs 1; AdapterBase.cs 1; ToolbarAdapter.cs 1; PersistenceProvider.cs 1; xWindow.cs 11; ExportDialog.cs 5; FwXWindow.cs 4; GlobalSettingServices.cs 1; InterestingTextList.cs 2; LinkListener.cs 3; RecordBrowseView.cs 2; RecordClerk.cs 13; RecordEditView.cs 1; RecordList.cs 2; TextListeners.cs 1; XhtmlDocView.cs 1; XmlDocConfigureDlg.cs 1; XmlDocView.cs 1.
Mechanical checks. Every PropertyTable overload (
SetProperty3- and 4-argument,SetDefault3- and 4-argument) takes the broadcast flag last, andSetPropertyInternalconsults it only to decide whether to callBroadcastPropertyChange. A scan ofgit diff -U0found 113 pairs whose lines differ by one trailingtruebecomingfalse, pure deletions in the three listener files, and nothing else. The extractor, re-run after the change, reports 427 rows before and after, 113 rows differing, every differencetruetofalsewith the value and settings-group columns unchanged, and the changed set equal to the inventory's dead list. No comment near a flipped site claims the broadcast matters.Mediator timing. One queued job is processed per posted
WM_BROADCAST_ITEM_INQUEUEmessage, but removing an item from that FIFO queue does not reorder the live jobs or theBeginInvokecallbacks around them, so no ordering changes for the sites that still broadcast.Tests.
test.ps1 -CommentHygiene -TokenHygiene -SkipNative -StartedBy agent -TestProject <name>: XMLViewsTests 117 passed; xCoreInterfacesTests 19 passed; DetailControlsTests 124 passed, 1 skipped; LexTextDllTests 10 passed; xWorksTests 1777 passed, 2 skipped. After the XmlSeqView local cleanup: rebuilt with tests, XMLViewsTests 117 passed again.Preflight review details
Code Review Summary
Branch: claude/pubsub-dead-broadcasts-8a2456
Base: main
Date: 2026-10-09
Review model: Claude Fable 5.1 (Claude Code)
Files changed: 55
Overview
The branch is the first step of moving xCore PropertyTable change notification (
PropertyTable.SetPropertywith the broadcast flag, which queues a Mediator "OnPropertyChanged" job) to the FwUtils publish/subscribe system: it removes the dead traffic in both directions before any ordering or timing work starts. An inventory of every production SetProperty/SetDefault site against every OnPropertyChanged handler (kept in a gitignored working folder, not in the tree) classified 113 of 176 live broadcasting sites as dead, meaning no registered colleague has a branch for the name. Those 113 sites now pass false for the broadcast flag and nothing else on the line changes. In the other direction, the two handler branches whose names nothing broadcasts are removed, with the two tests that drove one of them directly.The analysis found no Critical or Important issue. The diff was verified mechanically: every changed line in the first commit differs only by one trailing
truebecomingfalse; every PropertyTable overload takes that flag last; the extractor that produced the inventory, re-run on the branch, reports exactly the 113 inventoried rows changed and nothing else. The one name-independent handler side effect in the code base (ReversalClerk purging the sort-sequence cache folder on every broadcast it receives) changes frequency in the reversal tools but has no observable effect, because the cache's restore path never restores anything.Contract/API Changes
XmlBrowseView.OnPropertyChanged(string)andXmlSeqView.OnPropertyChanged(string)(public overrides) are removed. The inheritedSimpleRootSite.OnPropertyChangedserves both types; the Mediator resolves the method by name on the type, so no caller or reflection path breaks. No signature, serialized format, settings key, resource key or script contract changed. Settings persistence at every flipped site is unchanged (value, settings group and persistence calls stay).Findings
Critical - Must address before merge
None.
Important - Should address before merge
None.
Minor - Consider
(author: state it in the PR description, not the commit message; no runtime effect becauseSrc/LexText/Lexicon/ReversalListener.cs:581: the first commit's body says only the queued job goes away, but ReversalClerk callswindow.ClearInvalidatedStoredData()before examining the name, so in the two reversal tools dead broadcasts also purged the sort-sequence cache folder; now only live ones do.RecordList.RestoreFromnever restores)Src/Common/Controls/XMLViews/XmlSeqView.cs: with its handler gone,m_fShowFailingItemswas written and read only inside MakeRoot. (fixed during review: the field became a local in MakeRoot; the author asked for the cleanup and for it to be mentioned in the PR description)(author: no change needed; the commit body records the reasoning)Src/xWorks/XmlDocConfigureDlg.cs:1198: this flip rests on configuration facts (the only reachable layout-property names are NotebookPublicationLayout and null) rather than on an absent handler;RecordDocView.OnConfigureXmlDocViewstill falls back to DictionaryPublicationLayout, which XhtmlDocView handles.Required Validation / Evidence
.\build.ps1 -CommentHygiene -TokenHygiene: both hygiene gates clean, build succeeded, 0 warnings, 0 errors..\test.ps1 -CommentHygiene -TokenHygiene -SkipNative -StartedBy agent -TestProject <name>(the first run built the test assemblies, later runs used-NoBuild): XMLViewsTests 117 passed; xCoreInterfacesTests 19 passed; DetailControlsTests 124 passed, 1 skipped; LexTextDllTests 10 passed; xWorksTests 1777 passed, 2 skipped. No failures.Positive Observations
Interview Notes
In-Review Quality Check
The XmlSeqView field-to-local cleanup was made before the commits were created (the author asked for the review first), so it is part of the second commit rather than a separate fix-up. Rebuilt with tests and reran XMLViewsTests afterwards: 0 warnings, 0 errors, 117 passed.
Suggested Review Focus
trueminus the XML-driven family members.readOnlyBrowsesetter anywhere; the onlyShowFailingItems-button belongs to a tool whose view is XhtmlDocView, and XmlSeqView is hosted only by the Notebook Document tool.🤖 Generated with Claude Code
This change is