Repository navigation
Conversation
A Get*Property or GetValue read with a default, and SetDefault, now
store the value for an absent key without queueing OnPropertyChanged,
and SetDefault has no broadcast flag. Until now the first reader of an
unset property was a hidden setter: it created the key and queued a
broadcast of the default, so a handler could run on a placeholder
before the real value was set.
Dropping that broadcast loses nothing a handler could use. A handler
receives only the name and reads the table when the queued item drains,
which is after the code that read the default has set the real value;
so the read's item either repeated the set's own broadcast with the
same value, or delivered a placeholder nobody wanted (null, "" or
"????") when no set followed. At startup the first view was built on
the null currentContentControl item from the primed menus; it is now
built on AreaListener's own set, which queues right behind it with the
same parameters node.
The names whose first read used to reach a live handler, now stored
silently:
* currentContentControl and areaChoice (null, at window build, every
launch, because their persistence is switched off)
* BestStyleName ("????" from the Styles combo at the first idle)
* InterlinearTab ("" from the Parser menu at window build)
* ShowHiddenFields-<tool> (one per tool), ShowFailingItems-
lexiconClassifiedDictionary, ShowInvisibleSpaces and
ClickInvisibleSpace (pane-bar and menu items)
* DictionaryPublicationLayout and ReversalIndexPublicationLayout (""
before GetCurrentConfiguration sets the path)
* currentFilterForRecordClerk_<id> and ReversalIndexGuid
The SetDefault flag never reached a colleague: the window-level config
defaults load before any colleague registers, the tool-level ones find
their keys already set, and every code caller passed false.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1213 +/- ##
==========================================
+ Coverage 40.09% 40.29% +0.19%
==========================================
Files 1544 1547 +3
Lines 355309 355551 +242
Branches 41357 41446 +89
==========================================
+ Hits 142475 143255 +780
+ Misses 183533 182978 -555
- Partials 29301 29318 +17
🚀 New features to boost your workflow:
|
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/XCore/xCoreInterfaces/PropertyTable.cs,GetValueInternaland the twoSetDefaultoverloads: the whole behaviour change is those three methods; every other file only drops an argument.A read with a default (
GetBoolProperty,GetStringProperty,GetIntProperty,GetValue<T>(name, default)) andSetDefaultstill create the key when it is absent, but no longer queueOnPropertyChangedfor it.SetDefaultloses itsdoBroadcastIfChangedparameter. Until now the first reader of an unset property was a hidden setter that broadcast its placeholder (null,"","????") before the real value was set.The unknown is "which handler stops being called?". None that could use the call. A handler receives only the name and reads the table when the queued item drains, after the code that read the default has set the real value, so the read's item either repeated the set's own broadcast or carried a placeholder. The review question is therefore the per-name list below, not the engine line.
Where to look:
currentContentControlitem from the primed menus; it is now built on AreaListener's own set, queued right behind it with the samecurrentContentControlParametersnode (xWindow.OnPropertyChanged). Pinned by the fresh-launch probes.SetDefaultflag removal. The flag never reached a colleague: the window-level config defaults load before any colleague registers, the tool-level ones find their keys already set, and the four code callers passedfalse.DataTree.cs:1073callsSetPropertyPersistenceon a key its read just created;SetPropertyPersistencethrows on a missing key. The store stays, only the broadcast goes.SidebarAdapterSelectionTests,RawTextPaneTests) can only get easier; both pass.Deliberately not here: the choice groups'
"????"sentinel reads (ChoiceGroup.SinglePropertyValue) still store that placeholder; harmless, left alone. The read-then-set sites (EditingHelper,GetCurrentConfiguration) keep their real-value broadcast and convert as ordinary rows later.Verification: build with both hygiene gates; xCoreInterfacesTests 20 passed including the new colleague-spy test
GetWithDefaultAndSetDefault_StoreWithoutBroadcast; the two filtered runs above; two fresh-launch probes with persisted keys identical to the baseline build; six manual checks on Sena 3 (details below). Not run: the full suite, left to CI.Next: approve, or name a handler you believe depended on the placeholder broadcast.
Reading this a year from now -- start here
This PR is one step of converting
PropertyTable.BroadcastPropertyChange(MediatorOnPropertyChanged) to the FwUtils Pub/Sub system. The enumeration that justified it (303 default-carrying read sites, 111 names, which 12 reached a live handler and when) lives in the gitignored working inventoryDocs/migration/working/propertytable-broadcast-buckets.md, section 0, and its per-site table beside it. Nothing was deleted from the tree for this PR.Decisions, and why
SetPropertyPersistencethrows on a missing key) and changes BestSettings local-versus-global resolution and what gets persisted.SetDefaultflag instead of passingfalse. No caller benefited fromtrue, and a parameter that promises a broadcast which cannot happen misleads the next reader. The method comments say what the method does and do not mention broadcasting, since the Mediator broadcast is on its way out."????"sentinel. It is a config default (ChoiceGroup.cs,defaultPropertyValueabsent) that the first selection change replaces; after this PR it stores silently and nothing reads it for display.Evidence
Names whose first read used to reach a live handler, with what the placeholder was and who heard it:
currentContentControl,areaChoice: null at window build, every launch (persistence off in AreaListener); xWindow/FwXWindow, AreaListener, NavBarAdapter.BestStyleName:"????"from the Styles combo at the first active idle; xWindow, every SimpleRootSite.InterlinearTab:""from the Parser menu'sInInterlinearTextat window build; InterlinMaster.ShowHiddenFields-<tool>,ShowFailingItems-lexiconClassifiedDictionary,ShowInvisibleSpaces,ClickInvisibleSpace: pane-bar and menu items at window build or tool entry; DataTree, RecordEditView, PaneBar, XhtmlDocView, RawTextPane.DictionaryPublicationLayout,ReversalIndexPublicationLayout:""inGetCurrentConfigurationbefore it sets the path; XhtmlDocView, ReversalClerk.currentFilterForRecordClerk_<id>,ReversalIndexGuid: the clerk's own handler, ExportDialog's export-time read.Fresh-launch probes (project test222222, its
ConfigurationSettingsset aside, window activated so idle work runs,CloseMainWindow): straight into lexiconEdit and straight into lexiconClassifiedDictionary, on the baseline build and on this branch. Persisted keys identical in names and values (48 and 40 keys). No error dialog.Manual checks on Sena 3, all passed:
Preflight review details
Code Review Summary
Branch: claude/pubsub-silent-defaults-aa1873
Base: main (merge base 5cbbfe8)
Date: 2026-10-28
Review model: Claude Fable 5.1
Files changed: 6
Contract/API Changes
PropertyTable.SetDefault(string, object, bool)->SetDefault(string, object).PropertyTable.SetDefault(string, object, SettingsGroup, bool)->SetDefault(string, object, SettingsGroup).OnPropertyChanged; it still creates the key.Srcand updated: xWindow (4), DataTree, BrowseViewer (2), RecordClerk, PropertyTableTests (21).Findings
Critical: none. Important: none.
Minor, all fixed during review: dead
SetDefaultInternalcall inGetValueInternal's null-value branch removed; the new test now covers the null-valued-key branch; bounded drain loop;ProcessMessagesasserted before the negative assertion; using directives instead of fully qualified names; BestSettings overload summary reworded.Required Validation / Evidence
.\build.ps1 -CommentHygiene -TokenHygiene: clean..\test.ps1 -TestProject Src/XCore/xCoreInterfaces/xCoreInterfacesTests: 20 passed..\test.ps1 -TestProject Src/XCore/xCoreTests -TestFilter SidebarAdapterSelectionTests: 4 passed;-TestProject Src/LexText/Interlinear/ITextDllTests -TestFilter RawTextPaneTests: 2 passed.Interview Notes
Nothing further flagged by the author; PR title equals the commit title. Developer-only change, no Jira ticket.
Suggested Review Focus
PropertyTable.GetValueInternal: the null-value branch now stores directly with no further call.SetDefaultwith the old four-argument shape.🤖 Generated with Claude Code
This change is