Skip to content

Commit ab7e529

Browse files
committed
Add Lexical Edit Avalonia migration plan and coverage
Add FieldWorks Avalonia migration review skills Narrow Phase 1-2 Avalonia migration foundation
1 parent b0bf8a8 commit ab7e529

50 files changed

Lines changed: 3618 additions & 59 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
applyTo: "**/*"
3+
name: "avalonia.instructions"
4+
description: "Guidance for FieldWorks Avalonia modules and the shared Preview Host"
5+
---
6+
7+
# Avalonia Modules (FieldWorks)
8+
9+
## Purpose & Scope
10+
- Provide a consistent way to **create, build, test, and preview** Avalonia UI modules in FieldWorks.
11+
- Applies to the Advanced Entry Avalonia work under `specs/010-advanced-entry-view/` and future Avalonia modules.
12+
13+
## Key Rules
14+
15+
### Build & test (always use repo scripts)
16+
- Build the repo using the traversal script:
17+
- `./build.ps1`
18+
- Run tests using the repo test runner:
19+
- `./test.ps1`
20+
- Do **not** rely on `dotnet build` for repo-wide builds; FieldWorks build targets include tasks that require full Visual Studio/MSBuild.
21+
22+
### Project locations & naming
23+
- Feature modules live under `Src/<Area>/<Feature>.Avalonia/`.
24+
- Example: `Src/LexText/AdvancedEntry.Avalonia/`
25+
- Shared Avalonia utilities live under `Src/Common/FwAvalonia/`.
26+
- Preview tooling lives under `Src/Common/FwAvaloniaPreviewHost/`.
27+
28+
### Solution + traversal integration (required)
29+
For every new Avalonia module or tool:
30+
- Add the project(s) to the traversal build so `./build.ps1` and `./test.ps1` naturally cover them:
31+
- `FieldWorks.proj`
32+
- Add the project(s) to the solution so developers can open/build/debug in Visual Studio:
33+
- `FieldWorks.sln`
34+
35+
### Logging (use FieldWorks diagnostics)
36+
- Module logging must route through the existing FieldWorks diagnostics pipeline (`System.Diagnostics`, `TraceSwitch`, `EnvVarTraceListener`).
37+
- Add a `TraceSwitch` entry for each module/component in the dev diagnostics config:
38+
- `Src/Common/FieldWorks/FieldWorks.Diagnostics.dev.config`
39+
40+
### Preview Host diagnostics (log file)
41+
- The Preview Host writes startup errors and trace output to a log file next to the executable:
42+
- `Output/<Configuration>/FieldWorks.trace.log` (e.g. `Output/Debug/FieldWorks.trace.log`)
43+
- To override the log path, set environment variable `FW_PREVIEW_TRACE_LOG` to a full file path.
44+
45+
### Preview Host (fast UI iteration)
46+
To preview UI without launching the full FieldWorks app, use the shared Preview Host.
47+
48+
**How modules opt-in**
49+
- Register the module using an assembly-level attribute:
50+
- `FwPreviewModuleAttribute` in `Src/Common/FwAvalonia/Preview/`
51+
- Provide an optional data provider implementing:
52+
- `IFwPreviewDataProvider`
53+
54+
**Run the preview**
55+
- Use the agent script (build + run):
56+
- `./scripts/Agent/Run-AvaloniaPreview.ps1 -Module advanced-entry -Data sample`
57+
- Supported `-Data` modes depend on the module’s data provider; the current convention is:
58+
- `empty` (minimal/default DataContext)
59+
- `sample` (representative sample data)
60+
61+
## Expected Structure (current)
62+
63+
- Module:
64+
- `Src/LexText/AdvancedEntry.Avalonia/`
65+
- Shared utilities/contracts:
66+
- `Src/Common/FwAvalonia/`
67+
- `Diagnostics/` (logging shim)
68+
- `Preview/` (module registration + data provider contracts)
69+
- Preview host executable:
70+
- `Src/Common/FwAvaloniaPreviewHost/`
71+
- Launcher script:
72+
- `scripts/Agent/Run-AvaloniaPreview.ps1`
73+
74+
## Examples
75+
76+
### Build everything (recommended)
77+
```powershell
78+
./build.ps1
79+
```
80+
81+
### Run tests
82+
```powershell
83+
./test.ps1
84+
```
85+
86+
### Preview the Advanced Entry module
87+
```powershell
88+
./scripts/Agent/Run-AvaloniaPreview.ps1 -Module advanced-entry -Data sample
89+
```
90+
91+
## Notes & Constraints
92+
- Avalonia modules should remain **detached from LCModel** for preview scenarios (use DTO/view-model sample data) to keep the Preview Host lightweight.
93+
- Keep all user-visible strings localizable (use `.resx` patterns where applicable; do not hardcode translatable UI text).
94+
- Treat any input that crosses managed/native boundaries as untrusted; sanitize and validate per repo security guidance.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
name: fieldworks-avalonia-ui
3+
description: Use when creating, reviewing, or fixing Avalonia UI modules in FieldWorks, especially XAML, MVVM, preview-host, localization, accessibility, or net8 Avalonia test changes.
4+
---
5+
6+
# FieldWorks Avalonia UI
7+
8+
## Use This For
9+
- Avalonia XAML, view models, commands, lifetimes, dispatching, and resource/style changes.
10+
- New or changed projects under `Src/**/**/*.Avalonia/`, `Src/Common/FwAvalonia/`, and `Src/Common/FwAvaloniaPreviewHost/`.
11+
- Preview Host module registration, sample data providers, and UI diagnostics.
12+
13+
## Required Checks
14+
- Use current Avalonia docs for uncertain APIs; do not guess dispatcher, headless, automation, or binding behavior.
15+
- Keep product UI strings localizable; prototype hardcoded strings must be called out as gaps.
16+
- Stable accessibility identity belongs on user-facing controls via Avalonia automation properties.
17+
- UI work should stay in bindings/view models where practical; avoid logic-heavy code-behind.
18+
- Keep module preview data lightweight unless the change explicitly opts into LCModel/project data.
19+
- Preserve repo build/test entry points: `./build.ps1` and `./test.ps1`.
20+
21+
## Review Red Flags
22+
- A Common project directly references a feature module without an explicit architecture decision.
23+
- Preview-only code is launched from product UI without a feature gate and real-project behavior story.
24+
- Sleep-based or timing-sensitive UI tests.
25+
- Claims of accessibility, localization, IME, or keyboard parity without executable evidence.
26+
27+
## Handoff
28+
Report exact Avalonia docs consulted, tests run, remaining prototype gaps, and whether the change is product-facing or preview-only.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
name: fieldworks-managed-netfx-review
3+
description: Use when reviewing or changing FieldWorks managed C# projects that cross .NET Framework 4.8, C# 7.3, SDK-style net8, tests, or project-file boundaries.
4+
---
5+
6+
# FieldWorks Managed NetFx Review
7+
8+
## Compatibility Split
9+
- Legacy product code is .NET Framework 4.8 and C# 7.3 unless a project explicitly targets modern .NET.
10+
- New Avalonia modules may target `net8.0-windows`; do not leak C# 8+ syntax or net8-only APIs into net48 projects.
11+
- Legacy `.csproj` files require explicit source inclusion; SDK-style projects have different defaults.
12+
13+
## Required Checks
14+
- User-visible strings use `.resx` patterns where product-facing.
15+
- UI and async code marshals to the correct UI thread and does not use sync-over-async.
16+
- Disposable WinForms/GDI/LCModel/test resources are owned and disposed deterministically.
17+
- Test discovery changes must be validated across both net48 and net8 test assemblies.
18+
- Use repo scripts for evidence: `./build.ps1` and `./test.ps1`.
19+
20+
## Review Red Flags
21+
- Nullable annotations, records, file-scoped namespaces, switch expressions, or `using var` in net48/C# 7.3 projects.
22+
- Broad project/test-runner changes justified only by one local test passing.
23+
- Hardcoded Debug paths or absolute repo assumptions in tests.
24+
- Skipped tests used as evidence of covered behavior.
25+
26+
## Handoff
27+
Report target frameworks touched, project-file implications, test commands/results, and any remaining compatibility risks.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: fieldworks-migration-scope-review
3+
description: Use when reviewing large FieldWorks migration PRs, OpenSpec changes, foundational branches, scope splits, draft PR readiness, or evidence claims.
4+
---
5+
6+
# FieldWorks Migration Scope Review
7+
8+
## Review Posture
9+
Treat foundational migration PRs as architecture and evidence packages. The main question is whether reviewers can trust the scope, claims, and validation boundary.
10+
11+
## Required Checks
12+
- Compare PR title/body/tasks against the actual diff.
13+
- Classify files as plan/spec, characterization test, infrastructure, prototype, product behavior, or unrelated change.
14+
- Verify checked tasks match evidence language; downgrade claims when evidence says substitute, placeholder, skipped, future, or partial.
15+
- Confirm validation gates are explicit: OpenSpec validation, targeted tests, `./build.ps1`, and `CI: Full local check` when ready.
16+
17+
## Split Triggers
18+
- Product-visible behavior appears in a planning/test PR.
19+
- Common infrastructure directly depends on the first feature module without an explicit decision.
20+
- Test-runner/build graph changes are mixed with UI migration work.
21+
- Unrelated behavior changes require their own review context.
22+
23+
## Review Red Flags
24+
- A draft PR is so broad that each reviewer must reverse-engineer intent.
25+
- Evidence is stale after rebase or differs from visible CI state.
26+
- A prototype is wired as if it were a product feature.
27+
28+
## Handoff
29+
Lead with blockers, then list what to remove, split, reword, or validate before review.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: fieldworks-semantic-render-parity
3+
description: Use when capturing or reviewing FieldWorks semantic snapshots, render baselines, layout parity, failure artifacts, XML view definitions, or Avalonia presentation IR.
4+
---
5+
6+
# FieldWorks Semantic Render Parity
7+
8+
## Snapshot Discipline
9+
Semantic snapshots should preserve behaviorally meaningful identity and omit incidental layout noise.
10+
11+
## Include
12+
- Stable node ID and source layout/part identity.
13+
- Object/class binding, field/flid binding, editor kind, writing-system metadata, visibility, ghost state, expansion, focus order, localization key, and accessibility identity.
14+
- Unsupported construct diagnostics with enough path context to fix the source layout.
15+
16+
## Exclude Or Normalize
17+
- Pixel bounds, transient generated names, timestamps, machine paths, culture-dependent ordering, and realized-control counts unless the test explicitly owns them.
18+
19+
## Render Evidence
20+
- Pixel/render tests need deterministic fixtures, clear thresholds, and failure artifacts that reviewers can inspect.
21+
- A semantic snapshot is not a substitute for visual/render parity when typography, density, wrapping, or native rendering seams are under review.
22+
23+
## Review Red Flags
24+
- Placeholder metadata is presented as real binding or writing-system parity.
25+
- Snapshot tests update large JSON blobs without a small behavioral explanation.
26+
- Cache invalidation tests depend on sleeps or filesystem timestamp luck.
27+
28+
## Handoff
29+
State whether evidence is semantic, visual, accessibility, or performance parity, and identify remaining unproven axes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
name: fieldworks-uia2-parity-testing
3+
description: Use when designing or reviewing FieldWorks UI automation, UIA2, FlaUI, Appium, WinAppDriver, Avalonia.Headless, accessibility, keyboard, focus, or IME parity tests.
4+
---
5+
6+
# FieldWorks UIA2 Parity Testing
7+
8+
## Lane Separation
9+
- Avalonia.Headless is for fast in-process control, layout, view-model, binding, and input tests.
10+
- UIA2/FlaUI/Appium/WinAppDriver tests require realized desktop windows and validate native accessibility trees, focus, invoke patterns, and product integration.
11+
- Do not call a headless smoke test a UIA2 baseline.
12+
13+
## Required Evidence
14+
- Stable automation IDs or accessible names for controls under test.
15+
- Explicit coverage of focus movement, invoke/click path, popup/chooser reachability, keyboard shortcuts, and failure artifacts.
16+
- Clear CI lane: headless can run broadly; desktop automation needs an interactive Windows desktop or a configured automation host.
17+
18+
## Review Red Flags
19+
- “Runs in the background” used for UIA2/Appium without explaining the required desktop/session.
20+
- Tests assert implementation internals instead of user-observable accessibility behavior.
21+
- Automation selectors rely on localized labels when stable IDs are available or required.
22+
- IME coverage is claimed without a real text editor/control surface and input-method evidence.
23+
24+
## Handoff
25+
Classify each test as headless, native desktop automation, or smoke substitute, and state what parity claim it can and cannot support.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
name: fieldworks-winforms-to-avalonia-migration
3+
description: Use when planning, reviewing, or implementing FieldWorks WinForms/xWorks/DataTree/XMLViews migration paths to Avalonia, including seam extraction and parity coverage.
4+
---
5+
6+
# FieldWorks WinForms To Avalonia Migration
7+
8+
## Core Rule
9+
Migrate by proving behavior first, extracting seams second, and introducing Avalonia controls only after legacy behavior has executable parity evidence.
10+
11+
## Required Baselines
12+
- Entry points: `RecordEditView`, `DataTree`, `SliceFactory`, XMLViews browse/table views, launchers, popup choosers, and command/listener wiring.
13+
- Semantics: object/class binding, flid/field binding, labels, visibility, ghost state, expansion, focus order, writing-system metadata, accessibility identity, and localization keys.
14+
- User workflows: create/edit/save/cancel, chooser OK/cancel, undo/redo, refresh/postponed `PropChanged`, keyboard focus restoration, and disposal/unsubscribe.
15+
16+
## Architecture Checks
17+
- Keep WinForms Designer-safe code isolated from extracted logic.
18+
- Extract humble objects/services for modal decisions and data-loss classifiers before replacing controls.
19+
- Put an editor registry or adapter boundary in front of legacy `SliceFactory` behavior before mixing legacy and Avalonia editors.
20+
- Treat product command wiring as product behavior, not preview scaffolding.
21+
22+
## Review Red Flags
23+
- A PR mixes plans, tests, infrastructure, product UI wiring, and unrelated behavior changes.
24+
- Task checkboxes claim UIA2/IME/accessibility/localization parity while evidence says substitute, placeholder, skipped, or future work.
25+
- Avalonia preview data modifies or pretends to modify real project data without a real edit-session contract.
26+
27+
## Handoff
28+
State what is legacy baseline, what is extracted seam, what is Avalonia prototype, and what remains outside parity.

Src/Common/Controls/DetailControls/DetailControlsTests/DataTreeTests.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,31 @@ public void TwoStringAttr()
197197
Assert.That((m_dtree.Controls[1] as Slice).Label, Is.EqualTo("Bibliography"));
198198
}
199199

200+
[Test]
201+
public void CfAndBib_SemanticSliceBaselineCapturesStableBindingsAndFocusOrder()
202+
{
203+
m_dtree.Initialize(Cache, false, m_layouts, m_parts);
204+
m_dtree.ShowObject(m_entry, "CfAndBib", null, m_entry, false);
205+
Assert.That(m_dtree.Controls.Count, Is.EqualTo(2));
206+
207+
AssertSemanticSlice(
208+
m_dtree.Controls[0] as Slice,
209+
0,
210+
"CitationForm",
211+
"CitationForm",
212+
LexEntryTags.kflidCitationForm,
213+
"multistring",
214+
null);
215+
AssertSemanticSlice(
216+
m_dtree.Controls[1] as Slice,
217+
1,
218+
"Bibliography",
219+
"Bibliography",
220+
LexEntryTags.kflidBibliography,
221+
"multistring",
222+
"ifdata");
223+
}
224+
200225
/// <summary></summary>
201226
[Test]
202227
public void LabelAbbreviations()
@@ -222,6 +247,28 @@ public void LabelAbbreviations()
222247
Assert.That(abbr2 == (m_dtree.Controls[2] as Slice).Abbreviation, Is.False);
223248
}
224249

250+
private void AssertSemanticSlice(
251+
Slice slice,
252+
int focusOrder,
253+
string label,
254+
string field,
255+
int flid,
256+
string editor,
257+
string visibility)
258+
{
259+
Assert.That(slice, Is.Not.Null, "Expected a realized slice at focus order {0}.", focusOrder);
260+
Assert.That(m_dtree.Controls.IndexOf(slice), Is.EqualTo(focusOrder));
261+
Assert.That(slice.Label, Is.EqualTo(label));
262+
Assert.That(slice.Object.Hvo, Is.EqualTo(m_entry.Hvo));
263+
Assert.That(slice.Object.ClassID, Is.EqualTo(LexEntryTags.kClassId));
264+
Assert.That(slice.ConfigurationNode.Attributes["field"].Value, Is.EqualTo(field));
265+
Assert.That(Cache.MetaDataCacheAccessor.GetFieldId2(LexEntryTags.kClassId, field, true), Is.EqualTo(flid));
266+
Assert.That(slice.ConfigurationNode.Attributes["editor"].Value, Is.EqualTo(editor));
267+
Assert.That(slice.CallerNode.Attributes["visibility"]?.Value, Is.EqualTo(visibility));
268+
Assert.That(slice.Expansion, Is.EqualTo(DataTree.TreeItemState.ktisFixed));
269+
Assert.That(slice.Control.AccessibleName, Is.EqualTo(label));
270+
}
271+
225272
/// <summary></summary>
226273
[Test]
227274
public void IfDataEmpty()

0 commit comments

Comments
 (0)