Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .github/instructions/avalonia.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
applyTo: "**/*"
name: "avalonia.instructions"
description: "Guidance for FieldWorks Avalonia modules and the shared Preview Host"
---

# Avalonia Modules (FieldWorks)

## Purpose & Scope
- Provide a consistent way to **create, build, test, and preview** Avalonia UI modules in FieldWorks.
- Applies to the Advanced Entry Avalonia work under `specs/010-advanced-entry-view/` and future Avalonia modules.

## Key Rules

### Build & test (always use repo scripts)
- Build the repo using the traversal script:
- `./build.ps1`
- Run tests using the repo test runner:
- `./test.ps1`
- Do **not** rely on `dotnet build` for repo-wide builds; FieldWorks build targets include tasks that require full Visual Studio/MSBuild.

### Project locations & naming
- Feature modules live under `Src/<Area>/<Feature>.Avalonia/`.
- Example: `Src/LexText/AdvancedEntry.Avalonia/`
- Shared Avalonia utilities live under `Src/Common/FwAvalonia/`.
- Preview tooling lives under `Src/Common/FwAvaloniaPreviewHost/`.

### Solution + traversal integration (required)
For every new Avalonia module or tool:
- Add the project(s) to the traversal build so `./build.ps1` and `./test.ps1` naturally cover them:
- `FieldWorks.proj`
- Add the project(s) to the solution so developers can open/build/debug in Visual Studio:
- `FieldWorks.sln`

### Logging (use FieldWorks diagnostics)
- Module logging must route through the existing FieldWorks diagnostics pipeline (`System.Diagnostics`, `TraceSwitch`, `EnvVarTraceListener`).
- Add a `TraceSwitch` entry for each module/component in the dev diagnostics config:
- `Src/Common/FieldWorks/FieldWorks.Diagnostics.dev.config`

### Preview Host diagnostics (log file)
- The Preview Host writes startup errors and trace output to a log file next to the executable:
- `Output/<Configuration>/FieldWorks.trace.log` (e.g. `Output/Debug/FieldWorks.trace.log`)
- To override the log path, set environment variable `FW_PREVIEW_TRACE_LOG` to a full file path.

### Preview Host (fast UI iteration)
To preview UI without launching the full FieldWorks app, use the shared Preview Host.

**How modules opt-in**
- Register the module using an assembly-level attribute:
- `FwPreviewModuleAttribute` in `Src/Common/FwAvalonia/Preview/`
- Provide an optional data provider implementing:
- `IFwPreviewDataProvider`

**Run the preview**
- Use the agent script (build + run):
- `./scripts/Agent/Run-AvaloniaPreview.ps1 -Module advanced-entry -Data sample`
- Supported `-Data` modes depend on the module’s data provider; the current convention is:
- `empty` (minimal/default DataContext)
- `sample` (representative sample data)

## Expected Structure (current)

- Module:
- `Src/LexText/AdvancedEntry.Avalonia/`
- Shared utilities/contracts:
- `Src/Common/FwAvalonia/`
- `Diagnostics/` (logging shim)
- `Preview/` (module registration + data provider contracts)
- Preview host executable:
- `Src/Common/FwAvaloniaPreviewHost/`
- Launcher script:
- `scripts/Agent/Run-AvaloniaPreview.ps1`

## Examples

### Build everything (recommended)
```powershell
./build.ps1
```

### Run tests
```powershell
./test.ps1
```

### Preview the Advanced Entry module
```powershell
./scripts/Agent/Run-AvaloniaPreview.ps1 -Module advanced-entry -Data sample
```

## Notes & Constraints
- Avalonia modules should remain **detached from LCModel** for preview scenarios (use DTO/view-model sample data) to keep the Preview Host lightweight.
- Keep all user-visible strings localizable (use `.resx` patterns where applicable; do not hardcode translatable UI text).
- Treat any input that crosses managed/native boundaries as untrusted; sanitize and validate per repo security guidance.
28 changes: 28 additions & 0 deletions .github/skills/fieldworks-avalonia-ui/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: fieldworks-avalonia-ui
description: Use when creating, reviewing, or fixing Avalonia UI modules in FieldWorks, especially XAML, MVVM, preview-host, localization, accessibility, or net8 Avalonia test changes.
---

# FieldWorks Avalonia UI

## Use This For
- Avalonia XAML, view models, commands, lifetimes, dispatching, and resource/style changes.
- New or changed projects under `Src/**/**/*.Avalonia/`, `Src/Common/FwAvalonia/`, and `Src/Common/FwAvaloniaPreviewHost/`.
- Preview Host module registration, sample data providers, and UI diagnostics.

## Required Checks
- Use current Avalonia docs for uncertain APIs; do not guess dispatcher, headless, automation, or binding behavior.
- Keep product UI strings localizable; prototype hardcoded strings must be called out as gaps.
- Stable accessibility identity belongs on user-facing controls via Avalonia automation properties.
- UI work should stay in bindings/view models where practical; avoid logic-heavy code-behind.
- Keep module preview data lightweight unless the change explicitly opts into LCModel/project data.
- Preserve repo build/test entry points: `./build.ps1` and `./test.ps1`.

## Review Red Flags
- A Common project directly references a feature module without an explicit architecture decision.
- Preview-only code is launched from product UI without a feature gate and real-project behavior story.
- Sleep-based or timing-sensitive UI tests.
- Claims of accessibility, localization, IME, or keyboard parity without executable evidence.

## Handoff
Report exact Avalonia docs consulted, tests run, remaining prototype gaps, and whether the change is product-facing or preview-only.
27 changes: 27 additions & 0 deletions .github/skills/fieldworks-managed-netfx-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: fieldworks-managed-netfx-review
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.
---

# FieldWorks Managed NetFx Review

## Compatibility Split
- Legacy product code is .NET Framework 4.8 and C# 7.3 unless a project explicitly targets modern .NET.
- New Avalonia modules may target `net8.0-windows`; do not leak C# 8+ syntax or net8-only APIs into net48 projects.
- Legacy `.csproj` files require explicit source inclusion; SDK-style projects have different defaults.

## Required Checks
- User-visible strings use `.resx` patterns where product-facing.
- UI and async code marshals to the correct UI thread and does not use sync-over-async.
- Disposable WinForms/GDI/LCModel/test resources are owned and disposed deterministically.
- Test discovery changes must be validated across both net48 and net8 test assemblies.
- Use repo scripts for evidence: `./build.ps1` and `./test.ps1`.

## Review Red Flags
- Nullable annotations, records, file-scoped namespaces, switch expressions, or `using var` in net48/C# 7.3 projects.
- Broad project/test-runner changes justified only by one local test passing.
- Hardcoded Debug paths or absolute repo assumptions in tests.
- Skipped tests used as evidence of covered behavior.

## Handoff
Report target frameworks touched, project-file implications, test commands/results, and any remaining compatibility risks.
29 changes: 29 additions & 0 deletions .github/skills/fieldworks-migration-scope-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: fieldworks-migration-scope-review
description: Use when reviewing large FieldWorks migration PRs, OpenSpec changes, foundational branches, scope splits, draft PR readiness, or evidence claims.
---

# FieldWorks Migration Scope Review

## Review Posture
Treat foundational migration PRs as architecture and evidence packages. The main question is whether reviewers can trust the scope, claims, and validation boundary.

## Required Checks
- Compare PR title/body/tasks against the actual diff.
- Classify files as plan/spec, characterization test, infrastructure, prototype, product behavior, or unrelated change.
- Verify checked tasks match evidence language; downgrade claims when evidence says substitute, placeholder, skipped, future, or partial.
- Confirm validation gates are explicit: OpenSpec validation, targeted tests, `./build.ps1`, and `CI: Full local check` when ready.

## Split Triggers
- Product-visible behavior appears in a planning/test PR.
- Common infrastructure directly depends on the first feature module without an explicit decision.
- Test-runner/build graph changes are mixed with UI migration work.
- Unrelated behavior changes require their own review context.

## Review Red Flags
- A draft PR is so broad that each reviewer must reverse-engineer intent.
- Evidence is stale after rebase or differs from visible CI state.
- A prototype is wired as if it were a product feature.

## Handoff
Lead with blockers, then list what to remove, split, reword, or validate before review.
29 changes: 29 additions & 0 deletions .github/skills/fieldworks-semantic-render-parity/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: fieldworks-semantic-render-parity
description: Use when capturing or reviewing FieldWorks semantic snapshots, render baselines, layout parity, failure artifacts, XML view definitions, or Avalonia presentation IR.
---

# FieldWorks Semantic Render Parity

## Snapshot Discipline
Semantic snapshots should preserve behaviorally meaningful identity and omit incidental layout noise.

## Include
- Stable node ID and source layout/part identity.
- Object/class binding, field/flid binding, editor kind, writing-system metadata, visibility, ghost state, expansion, focus order, localization key, and accessibility identity.
- Unsupported construct diagnostics with enough path context to fix the source layout.

## Exclude Or Normalize
- Pixel bounds, transient generated names, timestamps, machine paths, culture-dependent ordering, and realized-control counts unless the test explicitly owns them.

## Render Evidence
- Pixel/render tests need deterministic fixtures, clear thresholds, and failure artifacts that reviewers can inspect.
- A semantic snapshot is not a substitute for visual/render parity when typography, density, wrapping, or native rendering seams are under review.

## Review Red Flags
- Placeholder metadata is presented as real binding or writing-system parity.
- Snapshot tests update large JSON blobs without a small behavioral explanation.
- Cache invalidation tests depend on sleeps or filesystem timestamp luck.

## Handoff
State whether evidence is semantic, visual, accessibility, or performance parity, and identify remaining unproven axes.
25 changes: 25 additions & 0 deletions .github/skills/fieldworks-uia2-parity-testing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: fieldworks-uia2-parity-testing
description: Use when designing or reviewing FieldWorks UI automation, UIA2, FlaUI, Appium, WinAppDriver, Avalonia.Headless, accessibility, keyboard, focus, or IME parity tests.
---

# FieldWorks UIA2 Parity Testing

## Lane Separation
- Avalonia.Headless is for fast in-process control, layout, view-model, binding, and input tests.
- UIA2/FlaUI/Appium/WinAppDriver tests require realized desktop windows and validate native accessibility trees, focus, invoke patterns, and product integration.
- Do not call a headless smoke test a UIA2 baseline.

## Required Evidence
- Stable automation IDs or accessible names for controls under test.
- Explicit coverage of focus movement, invoke/click path, popup/chooser reachability, keyboard shortcuts, and failure artifacts.
- Clear CI lane: headless can run broadly; desktop automation needs an interactive Windows desktop or a configured automation host.

## Review Red Flags
- “Runs in the background” used for UIA2/Appium without explaining the required desktop/session.
- Tests assert implementation internals instead of user-observable accessibility behavior.
- Automation selectors rely on localized labels when stable IDs are available or required.
- IME coverage is claimed without a real text editor/control surface and input-method evidence.

## Handoff
Classify each test as headless, native desktop automation, or smoke substitute, and state what parity claim it can and cannot support.
28 changes: 28 additions & 0 deletions .github/skills/fieldworks-winforms-to-avalonia-migration/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: fieldworks-winforms-to-avalonia-migration
description: Use when planning, reviewing, or implementing FieldWorks WinForms/xWorks/DataTree/XMLViews migration paths to Avalonia, including seam extraction and parity coverage.
---

# FieldWorks WinForms To Avalonia Migration

## Core Rule
Migrate by proving behavior first, extracting seams second, and introducing Avalonia controls only after legacy behavior has executable parity evidence.

## Required Baselines
- Entry points: `RecordEditView`, `DataTree`, `SliceFactory`, XMLViews browse/table views, launchers, popup choosers, and command/listener wiring.
- Semantics: object/class binding, flid/field binding, labels, visibility, ghost state, expansion, focus order, writing-system metadata, accessibility identity, and localization keys.
- User workflows: create/edit/save/cancel, chooser OK/cancel, undo/redo, refresh/postponed `PropChanged`, keyboard focus restoration, and disposal/unsubscribe.

## Architecture Checks
- Keep WinForms Designer-safe code isolated from extracted logic.
- Extract humble objects/services for modal decisions and data-loss classifiers before replacing controls.
- Put an editor registry or adapter boundary in front of legacy `SliceFactory` behavior before mixing legacy and Avalonia editors.
- Treat product command wiring as product behavior, not preview scaffolding.

## Review Red Flags
- A PR mixes plans, tests, infrastructure, product UI wiring, and unrelated behavior changes.
- Task checkboxes claim UIA2/IME/accessibility/localization parity while evidence says substitute, placeholder, skipped, or future work.
- Avalonia preview data modifies or pretends to modify real project data without a real edit-session contract.

## Handoff
State what is legacy baseline, what is extracted seam, what is Avalonia prototype, and what remains outside parity.
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,31 @@ public void TwoStringAttr()
Assert.That((m_dtree.Controls[1] as Slice).Label, Is.EqualTo("Bibliography"));
}

[Test]
public void CfAndBib_SemanticSliceBaselineCapturesStableBindingsAndFocusOrder()
{
m_dtree.Initialize(Cache, false, m_layouts, m_parts);
m_dtree.ShowObject(m_entry, "CfAndBib", null, m_entry, false);
Assert.That(m_dtree.Controls.Count, Is.EqualTo(2));

AssertSemanticSlice(
m_dtree.Controls[0] as Slice,
0,
"CitationForm",
"CitationForm",
LexEntryTags.kflidCitationForm,
"multistring",
null);
AssertSemanticSlice(
m_dtree.Controls[1] as Slice,
1,
"Bibliography",
"Bibliography",
LexEntryTags.kflidBibliography,
"multistring",
"ifdata");
}

/// <summary></summary>
[Test]
public void LabelAbbreviations()
Expand All @@ -222,6 +247,28 @@ public void LabelAbbreviations()
Assert.That(abbr2 == (m_dtree.Controls[2] as Slice).Abbreviation, Is.False);
}

private void AssertSemanticSlice(
Slice slice,
int focusOrder,
string label,
string field,
int flid,
string editor,
string visibility)
{
Assert.That(slice, Is.Not.Null, "Expected a realized slice at focus order {0}.", focusOrder);
Assert.That(m_dtree.Controls.IndexOf(slice), Is.EqualTo(focusOrder));
Assert.That(slice.Label, Is.EqualTo(label));
Assert.That(slice.Object.Hvo, Is.EqualTo(m_entry.Hvo));
Assert.That(slice.Object.ClassID, Is.EqualTo(LexEntryTags.kClassId));
Assert.That(slice.ConfigurationNode.Attributes["field"].Value, Is.EqualTo(field));
Assert.That(Cache.MetaDataCacheAccessor.GetFieldId2(LexEntryTags.kClassId, field, true), Is.EqualTo(flid));
Assert.That(slice.ConfigurationNode.Attributes["editor"].Value, Is.EqualTo(editor));
Assert.That(slice.CallerNode.Attributes["visibility"]?.Value, Is.EqualTo(visibility));
Assert.That(slice.Expansion, Is.EqualTo(DataTree.TreeItemState.ktisFixed));
Assert.That(slice.Control.AccessibleName, Is.EqualTo(label));
}

/// <summary></summary>
[Test]
public void IfDataEmpty()
Expand Down
Loading
Loading