Phase-1 base: Avalonia migration spine (UIMode defaults Legacy)#964
Draft
johnml1135 wants to merge 5 commits into
Draft
Phase-1 base: Avalonia migration spine (UIMode defaults Legacy)#964johnml1135 wants to merge 5 commits into
johnml1135 wants to merge 5 commits into
Conversation
This was referenced Jun 24, 2026
3a905c6 to
b423a19
Compare
This comment has been minimized.
This comment has been minimized.
This was referenced Jul 1, 2026
johnml1135
added a commit
that referenced
this pull request
Jul 1, 2026
…ing docs Per deep review of the Phase-1 base PR, this removes ~10,300 lines of openspec content that does not belong in the base PR: Deleted entirely (self-declared superseded, or already implemented on a sibling branch with no home needed here): - openspec/changes/graphite-transition-support/ (self-labeled superseded throughout; content restated elsewhere) - openspec/changes/fieldworks-avalonia-shell-migration/ (self-labeled folded into/superseded by avalonia-end-game) - openspec/changes/avalonia-interlinear-editor/ (implemented on phase1-followup-interlinear, commit 3c5893e) - openspec/changes/avalonia-rule-formula-editor/ (implemented on phase1-followup-rule, commit 2c142bc) Deleted here for relocation to phase1-docs (speculative future-phase planning with real future value, not needed to review/merge this PR): - openspec/changes/avalonia-migration-roadmap/complete-migration-program.md, epics/**, reviews/** (JIRA-epic drafting for unstarted stages 5-13) - openspec/changes/legacy-screenshot-capture/ (dev tooling supporting a Docs/migration/ effort this PR isn't carrying) - openspec/changes/avalonia-end-game/ (depends on a Phase-1 burn-down this PR hasn't finished) Trimmed/deleted within datatree-model-view-separation (this change's own proposal.md/hybrid-alignment.md already carry a 2026-06-09 supersession note saying DataTreeModel/SliceSpec/IDataTreeView "should not be built"; these were the pieces that never caught up to that note): - Deleted specs/datatree-model/spec.md (asserted the abandoned DataTreeModel/SliceSpec/IDataTreeView requirements as live ADDED reqs); kept specs/datatree-partial-split/spec.md (the partial-class-split slice the proposal says remains valid as optional legacy maintenance) - Deleted three overlapping draft test plans for the abandoned design: testing-approach-2.md, test-plan-forms.md, test-plan-forms-future.md - Deleted stale coverage-gap planning docs: specs/changes-from-test-before-refactor/coverage-wave2-test-matrix.md and ".../tests to fix coverage gaps.md" - Trimmed datatree-mental-model.md to the current-state description only, removing the "target shape after split" section describing the abandoned architecture Fixed two stale artifacts that never caught up to their sibling supersession notes: - avalonia-migration-roadmap/specs/avalonia-migration-roadmap/spec.md: added a supersession note to the "DataTree split is the first migrated region" requirement and added an as-built scenario describing the actual region-model path (ViewDefinitionModel/LexicalEditRegionModel), matching the note already in this change's own design.md - lexical-edit-avalonia-migration/architecture-diagrams.md: removed the IPropertyStateStore port node (never built per task 18.6; state flows through IRecordNavigationContext + host PropertyTable), annotating the Navigation port instead Kept as-is per review: avalonia-migration-roadmap/{proposal,design, tasks}.md + specs/ (the ordered roadmap every later stack PR needs), avalonia-multi-writing-system-text-foundation/ (substantially shipped, not speculative), and the rest of datatree-model-view-separation (design.md/tasks.md/proposal.md already carry accurate snapshot framing). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
First of a 4-PR stack landing Phase 1 of the WinForms->Avalonia migration. Every Avalonia surface is gated behind the UIMode setting, which DEFAULTS TO "Legacy" (Src/Common/FwUtils/Properties/Settings.Designer.cs), so default users see no behavioral change. Contents: - The Avalonia migration framework: region/composer (FullEntryRegionComposer), the typed view-definition IR compiled from XML layouts, owned dense controls, the seam contracts, and the region-editor plugin registry. - The base detail-editor surfaces active under UIMode=New: lexiconEdit, lexiconEditPopup, notebookEdit, posEdit. - The Avalonia browse table (LexicalBrowseView, LexicalBrowseHostControl, BulkEditBarView, ClerkBrowse*) and its RecordBrowseView product wiring, shipped DORMANT (fused to base wiring; activated by the table follow-up PR). - 13 dialog UIs + a shared MessageBox riding behind UIMode=New, each verified wired to a real WinForms call site; 4 cleanly-removable unwired Avalonia dialogs backed out (SpecialCharacter, WritingSystemProperties, DeleteConfirmation, LexReferenceDetails). - ChorusNotesBarControl (the Chorus/FLExBridge notes bar) rides as a Phase-1 follow-up surface alongside the browse table and the interlinear/ rule-formula plugins -- built, but not registered in this base PR. - Migration skills/playbook (incl. the inert-surface activation recipe), the roadmap's core proposal/design/tasks/spec, and the landed openspec change specs (lexical-edit-avalonia-migration, shared-editable-virtualized-table, avalonia-multi-writing-system-text-foundation). The interlinear and rule-formula detail editors are carved out to their own stacked follow-up PRs; the inert tool lists are LexicalEditSurfaceRegistry.Phase1FollowUpSurfaceTools and LexicalEditSurfaceResolver.Phase1FollowUpBrowseTools. Migration per-screen docs (the JIRA-ticket basis) and the full 13-stage migration-program planning material live on the separate never-merged phase1-docs branch (the latter also mirrored to chore/relocate-roadmap-planning-docs). Phase 2 (avalonia-end-game: net multiplatform + shell conversion + WinForms removal) is planned only and gated on Phase 1 + tester burn-down; its proposal lives with the roadmap material above, not in this PR. Post-review cleanup folded into this commit (see PR_964_review.md for the full audit trail): - Removed content unrelated to this migration that had been swept in: an unrelated installer-docs deletion and an ungated Legacy-mode rendering change were reverted, and a misplaced/stale stray doc file was dropped. - Split two unrelated-but-legitimate fixes into their own PRs rather than carrying them here: #978 (VersionInfoProvider copyright/version-string bugs, a stale RegFree.targets entry, an opsx-prompt refactor) and #979 (a pre-existing cross-worktree test-collision bug in RealDataTestsBase, found while verifying this branch but unrelated to it). - Fixed a real build break (RecordBrowseView.cs used a pub/sub API signature main had already replaced) and a real product bug (the Avalonia refresh controller could stay unwired when a tool loads directly into UIMode=New, fixed in RecordEditView.cs). - Pared back ~7,500 lines of speculative future-phase openspec planning docs (the 13-stage migration program, legacy-screenshot-capture tooling, the end-game proposal) to a separate branch, and deleted two fully superseded proposals and stale DataTree-model-view-separation specs asserting an architecture that was never built. - Wired the one missing UIMode gate (GoLinkEntryDlgListener.OnGotoLexEntry), documented one honest parity deferral (MsaInflectionFeatureListDlgLauncher switch-tools navigation), removed dead API and orphaned localization keys, strengthened the FwAvalonia engine-isolation audit to match its own documented symbol list, fixed three evidence-language issues in Path3BundleTests, and reconciled dialog spacing tokens against real measured WinForms control geometry. Verification: whole-solution build green. Surface-registry census: 6 custom-slice classes classified (LexemeEditorBurnDownTests); 7 tools in LexicalEditSurfaceRegistry.Phase1FollowUpSurfaceTools; 8 tools in LexicalEditSurfaceResolver.Phase1FollowUpBrowseTools. Full CI-equivalent test run: all tests pass except 38 pre-existing, environment-specific RealDataTestsBase cross-worktree-collision failures (fix is PR #979, kept separate) and one test-harness limitation in RecordEditViewSwitchTests documented in PR_964_review.md (the underlying product bug is fixed; the test's idle-queue draining has a separate, deeper, pre-existing issue that needs its own follow-up). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up to the review's remaining small polish items: - Removed "POC"/"spike" language that mischaracterized shipped, active code as throwaway prototype work: Directory.Packages.props' Avalonia package group (was "POC spike only"), LexicalEditSurfaceResolver.cs's doc comments, OptionsDialogView.axaml.cs, dialog-conversion.md's "spike" section header, and two test project file headers. Also fixed a real, functional staleness this surfaced: scripts/Agent/Run-AvaloniaPreview.ps1's default -Module value and example were still "lexical-edit-poc", which does not match the actually-registered "lexical-edit-preview" module id in AssemblyPreviewModules.cs -- the documented default command would have silently found no module. - Fixed stale pointers to the renamed PocDensity.cs -> FwAvaloniaDensity.cs in fieldworks-avalonia-ui/SKILL.md and architecture-patterns.md. - Corrected two files describing DataTreeTimingBaselines.json as "committed" when it's gitignored and regenerated per machine. - Indexed Launch-FieldWorksInvisible.ps1 in fieldworks-winapp/SKILL.md's script list; it claimed default-launcher status but wasn't discoverable from the documented navigation path. - Deleted Docs/avalonia-migration-approach-comparison.md (a decision record for a decision already made and recorded elsewhere) and updated its three referencing files to point at the surviving decision record instead of a dead link. - Rewrote avalonia.instructions.md's forward references to a specs/010-advanced-entry-view/ spec and an AdvancedEntry.Avalonia module that don't exist in this repo, replacing them with the actual current structure and a real, working preview-module example. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
These are the screenshot-capture tools that produce the Docs/migration/ per-screen documentation (which itself lives entirely on the phase1-docs branch, not here) -- they belong with what they produce, not on the code migration branches. The openspec legacy-screenshot-capture proposal describing this tooling was already relocated in an earlier commit; these are the actual scripts it describes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The 5 new RecordEditView/region test fixtures each had a local DrainMediatorAndIdleQueues that invoked IdleQueue's private Application_Idle via reflection. That method's ShouldAbort() guard peeks the real Win32 message queue and bails out unconditionally in this test process (there is no real message loop), so queued idle work like RecordEditView.ShowRecordOnIdle never actually ran and these tests never exercised their target code path. Centralize a correct drain in XWorksAppTestBase that pumps IdleQueue's public ICollection surface directly instead. Running the real ShowRecordOnIdle path this way surfaced a second, previously-latent gap: RecordEditViewSwitchTests and RecordClerkNavigationContextTests never bootstrapped the legacy layout/parts Inventory that DataTree.ShowObject needs, causing an NRE the moment idle-queued work actually ran. Bootstrap it the same way RegionObjectCommandExecutionTests/ RegionCommandAdapterHardeningTests already do. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Test coverage (34 new tests, 0 production changes, 0 regressions): - Extend LcmMsaCreatorDialogLauncherTests/LcmInsertEntryDialogLauncherTests (already done in prior commit) plus the remaining 9 Lcm*Launcher classes' pure/testable logic: guard clauses, resolve/exclude branches, and the Inflection-vs-Phonological Apply(deleteWhenEmpty) divergence that was previously untested in either direction. - Add a regression test for the XmlViewsUtils.cs part-ref caller-propagation fix (verified it actually catches a reversion of that fix before finalizing). Doc/comment fixes (no behavior change): - RecordBrowseView.cs: correct a doc comment that overstated the Avalonia browse overlay as live for lexiconBrowse today (it's inert for every tool in this PR); cross-reference the "flip this array" mechanism with LexicalEditSurfaceResolver.cs so it's discoverable from either side. - Flag the 3 rule-formula composition test files as early groundwork that landed ahead of the avalonia-rule-formula-editor follow-up PR, and correct NaturalClassComposeTests.cs's overstated "flipped to Avalonia" claim. See PR_964_review.md §18 for the full 9-group gap triage, including which items were left as findings (production-restructuring or genuinely modal-locked) rather than force-fixed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4 tasks
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.
Phase-1 base: Avalonia migration spine
First of a 4-PR stack landing Phase 1 of the WinForms→Avalonia migration. Every Avalonia surface is gated behind the
UIModesetting, which defaults toLegacy(Src/Common/FwUtils/Properties/Settings.Designer.cs) — so default users see no change.What this PR contains
FullEntryRegionComposer), view-definition IR, owned controls, seam contracts, plugin registry.UIMode=New:lexiconEdit,lexiconEditPopup,notebookEdit,posEdit.LexicalBrowseView,LexicalBrowseHostControl,BulkEditBarView,ClerkBrowse*) and itsRecordBrowseViewwiring — shipped dormant (it's fused to base wiring and can't be cleanly carved out; activated by the table follow-up).lexical-edit-avalonia-migration,shared-editable-virtualized-table,avalonia-multi-writing-system-text-foundation) — pared back from the original diff (see "Branch cleanup" below).UIMode=New, each verified wired to a real WinForms call site.Inert follow-up surfaces
The interlinear and rule-formula detail editors are carved out to the stacked follow-up PRs below (their openspec proposals and view files are not in this PR). The browse table and
ChorusNotesBarControl(the Chorus/FLExBridge notes bar) ship here but inert. The inert lists areLexicalEditSurfaceRegistry.Phase1FollowUpSurfaceToolsandLexicalEditSurfaceResolver.Phase1FollowUpBrowseTools; the migration skill documents the activation recipe.Stack (each merges into the one above)
mainphase1-followup-interlinear→phase1-basephase1-followup-rule→phase1-followup-interlinearphase1-followup-table→phase1-followup-ruleMigration per-screen docs (the basis for JIRA tickets) and the full 13-stage migration-program planning material (speculative future-phase work, not needed to review this PR) both live on the separate, never-merged
phase1-docsbranch (draft PR, explicitly marked do-not-merge).Verification
Whole-solution build green. Surface-registry census: 6 custom-slice classes classified (
LexemeEditorBurnDownTests); 7 tools inLexicalEditSurfaceRegistry.Phase1FollowUpSurfaceTools; 8 tools inLexicalEditSurfaceResolver.Phase1FollowUpBrowseTools. Full CI-equivalent test run passes except 38 pre-existing, environment-specific test failures unrelated to this branch (a cross-worktree test-data collision, fixed separately in #979). Note: two of the hardening test files (RegionCommandAdapterHardeningTests.cs,RegionObjectCommandExecutionTests.cs) run roughly half their cases only on the manual[Explicit]desktop lane, not CI — "tests added" for these files should not be read as "tests running in CI." Draft until the stack is reviewed top-to-bottom.Branch cleanup (post-review)
A multi-part internal review of this branch (
PR_964_review.md, not included in this diff) found and fixed a substantial amount of unrelated or stale content bundled into the original diff. Squashed into this single commit; highlights:RegFree.targetsentry, an opsx-prompt refactor) and #979 (a pre-existing cross-worktree test-collision bug inRealDataTestsBase, found while verifying this branch but unrelated to it).RecordBrowseView.csused a pub/sub API signaturemainhad already replaced) and a real product bug (the Avalonia refresh controller could stay unwired when a tool loads directly intoUIMode=New) — and the test proving it (RecordEditViewSwitchTests) is now green: the shared idle-queue test-drain helper had never actually worked in this environment (it reflected into a private method whose message-pump politeness check always aborted), which also meant 5 test fixtures weren't proving what they looked like they proved. Centralized a correct drain inXWorksAppTestBase, which surfaced and fixed a second bug (2 fixtures missing a layout/partsInventorybootstrap 2 sibling fixtures already had). All affected tests pass; fullxWorksTestssuite: 1645 passed, 0 failed.datatree-model-view-separationspecs asserting an architecture that was never built, and removed remaining POC/spike language and stale cross-references repo-wide (including a real stale-default-value bug inRun-AvaloniaPreview.ps1).ChorusNotesBarControlas a Phase-1 follow-up surface (it was live, contradicting its "dormant" framing); wired the one missingUIModegate (GoLinkEntryDlgListener.OnGotoLexEntry); documented one honest parity deferral (MsaInflectionFeatureListDlgLauncherswitch-tools navigation); removed dead API and ~20 orphaned localization keys; strengthened the FwAvalonia engine-isolation audit to match its own documented symbol list; fixed three evidence-language issues inPath3BundleTests; reconciled dialog spacing tokens against real measured WinForms control geometry.ApplyInflectionFeatures's undo-task-safety null guards, anXmlViewsUtilspart-ref regression test, and the pure/testable logic across all remaining under-testedLcm*Launcherclasses), and documented the genuinely modal-locked gates that can't be unit-tested without a production testability seam. Full breakdown below.9-group breakdown: scope, gaps found, what was fixed vs. left as a finding
Every file in this PR's diff (562 files) is accounted for in exactly one of the 9 groups below (verified programmatically — zero unclassified). Full detail, file-by-file evidence, and exact test names are in
PR_964_review.md§18.Src/Common/FwAvalonia/{Region,ViewDefinition,Seams,Preview}/, rootFwAvalonia/*,FwAvaloniaPreviewHost/Preview/code ships inside the production DLL (excluding it would breakFwAvaloniaPreviewHost.exe's current project-reference wiring, a build-topology change);FwAvaloniaStrings.resxhas orphaned keys (deleting/rewiring changes shipped localization surface)FwAvaloniaTests/,FwAvaloniaDialogsTests/,RenderTestInfrastructure/,RenderVerification/AvaloniaHeadlessDialogFixtureBase(~24 files) and a sharedViewDefinitionModeltest-builder (~9 files) are DRY/maintainability refactors of existing, passing tests, not coverage gaps; real but non-trivial regression risk, recommended as a dedicated follow-up rather than bundled in hereFwAvaloniaDialogs/(excl. tests)Src/xWorks/*.cs(excl. tests),Common/Controls/,Common/FwUtils/,Common/FieldWorks/,XCore/,Common/Framework/,Common/SimpleRootSite/,Common/ViewsInterfaces/Src/xWorks/xWorksTestsSrc/LexText—LexTextControls/,Lexicon/,Morphology/,Interlinear/,LexTextDll/if (UIMode==New) {Avalonia} else {legacy}dialog-launcher gates; 13 newLcm*Launcherglue classesEntryDlgListener.cs, 3 gates;MSAPopupTreeManager.cs, 2 gates;LexReferenceMultiSlice.GetRootObject) — every path ends in a real modal dialog this codebase deliberately excludes from unit tests; fixing needs a production testability seam, a decision for whoever owns this PRdatatree-model-view-separation's oneopenspec validate --strictfailure predates this PR entirely — not this PR's scope to fix.claude/skills+.github.sln/.proj/Directory.Packages.props/root docsTotals: 12 gaps found across the PR: 7 fixed (35 new tests + 4 doc/comment corrections), 5 left as explicit findings (2 production-restructuring, 2 test-refactor-only, 1 pre-existing-elsewhere) — none silently dropped.
This change is