Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
d3865ff
Phase-1 base: Avalonia migration spine (UIMode defaults Legacy)
johnml1135 Jul 15, 2026
5555e46
Replace coined 'lane'/'chrome' vocabulary; fix skills consistency
jasonleenaylor Jul 24, 2026
c696beb
Move FieldWorks-owned Avalonia strings to the .resx strategy
jasonleenaylor Jul 24, 2026
bd7d3a5
Remove the inert Avalonia browse surface and unreachable staging code
jasonleenaylor Jul 24, 2026
ba37286
Fix UIMode startup seeding; harden edit-session and teardown guards
jasonleenaylor Jul 24, 2026
a973fb8
Add Go-family auxiliary selection; port the allomorph mismatch prompt
jasonleenaylor Jul 24, 2026
454c7b1
Trim process references and stale wording from recent comments
jasonleenaylor Jul 24, 2026
72a9754
Trim process references from the PR's original comments
jasonleenaylor Jul 24, 2026
4612aae
Give the Go-family search box vernacular typography and keyboard
jasonleenaylor Jul 24, 2026
487f948
Add the control/behavior-to-exemplar map with a gap register
jasonleenaylor Jul 24, 2026
863b944
Restore the persistent multi-column matching list in the Go dialog
jasonleenaylor Jul 24, 2026
0af87be
Settle fenced edits before the tool-switch commit
jasonleenaylor Jul 25, 2026
f6f5572
Give hosted Avalonia dialogs navigation keys and the owner icon
jasonleenaylor Jul 25, 2026
02e1454
Declutter the multi-WS field: right-click affordances, fixed WS gutter
jasonleenaylor Jul 27, 2026
de52e69
Stop the region context menu from doubling the shared slice commands
jasonleenaylor Jul 27, 2026
32c925b
Fix Shift+Arrow selection in the multi-WS field; pin selection with h…
jasonleenaylor Jul 27, 2026
1f70427
Keep the durable Avalonia selection gotchas; drop the stale note
jasonleenaylor Jul 28, 2026
ca58e38
Host the POS-chooser and option-picker dropdowns in flyouts, not free…
jasonleenaylor Jul 28, 2026
df74847
Trim the lexical-edit region to string, list-choice, and one native p…
jasonleenaylor Jul 28, 2026
88d4a58
Bring the Avalonia Insert Entry dialog to legacy parity
jasonleenaylor Jul 28, 2026
45a569a
Clean up the MSA and feature-structure editors into copyable exemplars
jasonleenaylor Jul 28, 2026
5067a69
Fix review-flagged doc-comment defects
jasonleenaylor Jul 28, 2026
0bc3b9f
Pin the FwAvaloniaPlatform reflection targets against Avalonia bumps
jasonleenaylor Jul 28, 2026
de9fe70
Split IRegionEditContext into sub-capability interfaces
jasonleenaylor Jul 28, 2026
d200a34
Collapse composer setter dictionaries into per-field edit handlers
jasonleenaylor Jul 28, 2026
9f684cd
Extract shared filterable-dropdown base for the region pickers
jasonleenaylor Jul 28, 2026
f409b5a
Decompose the FwMultiWsTextField constructor
jasonleenaylor Jul 28, 2026
d82088f
Audit PR comments: strip migration framing, doc markers, and absence …
jasonleenaylor Jul 29, 2026
bb485d3
Rename region data/model to the Region* vocabulary
jasonleenaylor Jul 29, 2026
cc815b9
Rename the region view to RegionDataTree
jasonleenaylor Jul 29, 2026
a7513ce
Rename the field-control factory to SliceFactory
jasonleenaylor Jul 29, 2026
f01248d
Rename the edit-surface family to EditSurface*
jasonleenaylor Jul 29, 2026
0e3ab4c
Rename the feature manager family to LexiconFeature*
jasonleenaylor Jul 29, 2026
ea6dfb8
Rename Lexicon-specific region types and relocate the WS-keyboard helper
jasonleenaylor Jul 29, 2026
0836472
Rename region support types to the generic vocabulary
jasonleenaylor Jul 29, 2026
5f56b0b
Rename converted dialogs to their legacy WinForms stems
jasonleenaylor Jul 29, 2026
71d4656
Corral the xWorks Avalonia region bridge into Avalonia/ subfolders
jasonleenaylor Jul 29, 2026
896e92d
Corral the LexTextControls Avalonia launchers into Avalonia/
jasonleenaylor Jul 29, 2026
ac50ecc
Mirror the Avalonia test folders to their SUTs
jasonleenaylor Jul 29, 2026
8d21d03
Use the bare SliceFactory stem for the Avalonia field-control factory
jasonleenaylor Jul 29, 2026
e0d002a
Evict non-seam types from the Seams namespace and split ISeams.cs
jasonleenaylor Jul 29, 2026
9621058
Align region terminology with legacy idioms
jasonleenaylor Jul 29, 2026
db27e24
Relabel the UI-mode toggle to New UI (preview)
jasonleenaylor Jul 29, 2026
fb0313e
Rename the region model and view to the Detail vocabulary
jasonleenaylor Jul 29, 2026
973a98a
Rename the composer, edit contexts, and slice plugins to the Detail v…
jasonleenaylor Jul 29, 2026
f729aa9
Rename preview, dialog, and keyboard support to the Detail vocabulary
jasonleenaylor Jul 29, 2026
7435ea1
Rename the region test suites to the Detail vocabulary
jasonleenaylor Jul 29, 2026
4f58fb2
Sweep region prose and resources to the Detail vocabulary
jasonleenaylor Jul 29, 2026
06bed8b
Rename Region-stale string literals to the Detail vocabulary
jasonleenaylor Jul 30, 2026
2c94256
Refresh skill docs to the current vocabulary and paths
jasonleenaylor Jul 30, 2026
16f9bb7
Add the dialog and slice conversion workflow skills and playbooks
jasonleenaylor Jul 30, 2026
35c7236
Protect the running app and make conversion gates real stops
jasonleenaylor Jul 30, 2026
079936d
Spell out ViewModel instead of the ambiguous VM abbreviation
jasonleenaylor Jul 30, 2026
7b9b9f0
Name the conversion stages instead of numbering them
jasonleenaylor Jul 30, 2026
ea72737
Retire migration working docs and align skills and specs to the tree
johnml1135 Jul 31, 2026
7571a56
Restore the Unicode punctuation flattened to question marks
johnml1135 Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
313 changes: 313 additions & 0 deletions .claude/skills/convert-dialog/SKILL.md

Large diffs are not rendered by default.

162 changes: 162 additions & 0 deletions .claude/skills/convert-slice/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
name: convert-slice
description: Drive the conversion of one legacy slice type to the Avalonia detail view through analysis, developer alignment, integration-test planning, route/exemplar mapping, design, and scaffold/implement. Use when the user invokes /convert-slice with a slice class or layout identity, or asks to convert a slice type or an Unsupported detail row.
---

# Convert Slice

The slice-type counterpart of convert-dialog: the same stages, gates, and
working-document conventions -- with the deltas a slice demands. The
developer decides and confirms; this skill analyzes, drafts, and builds.

## Two rules that override everything else

**1. The developer's FieldWorks is untouchable.** They are exploring the
slice while you work. NEVER close, kill, restart, or drive their running
FieldWorks, and never change the UI-mode setting under them. The live-app
capture route owns the app lifecycle (relaunch-per-tool, `CloseMainWindow`)
-- FORBIDDEN while their instance is open. Ask before any
`build.ps1`/`test.ps1` run: a build fails on binaries their app holds
locked, and killing their process to unblock it is never acceptable. On a
locked-file failure, STOP and ask.

**2. Every gate is a real stop.** A gate is an interactive question (use the
question tool, which returns only when they answer), then END the turn. Do
not summarize or restate a report in chat -- point at the file and stop; a
chat summary invites skipping the review the gate exists for.

## How to talk about where you are

Use the stage names with the developer, in plain language about the work --
never "Phase 2" or any numbered-stage shorthand. The stages, in order:
**Understanding the slice** -> **Agreeing on how it works** -> **Deciding
what to prove** -> **Planning the replacement** -> **Building it** ->
**Proving it works**.

Input: the legacy slice class name (e.g. `PhoneEnvReferenceSlice`) or the
layout identity (`editor="..."` / `editor="Custom" class="..."`).
Scope: PORT with low-cost improvements; a "redesign" verdict parks the
slice.

Working documents, resume rule, and ticket attachment are identical to
convert-dialog: `Docs/migration/working/<SliceClass>/` holding
`<SliceClass>-analysis.md`, `<SliceClass>-integration-test-plan.md`,
`<SliceClass>-design.md`; detect-and-resume on re-invocation; the documents
remain after completion (retention is the developer's call).

## Understanding the slice (read-only; safe while they explore)

Source, history, Jira, and layout-XML reading only -- no build, no test run,
no app automation -- so it runs concurrently with the developer's own
exploration. The "before" evidence is NOT part of that concurrent work.

Everything convert-dialog does when understanding a dialog (source + related
files, file history + Jira chronology, logic and data-member analysis incl.
LCM objects and Units of Work, enabled/disabled cataloging), plus
slice-specific work:

- Resolve the layout identity: the `editor=`/`class=` attributes and every
layout node that produces this slice.
- Inventory where it appears: which fields, which tools, roughly how many
instances (compose an affected record in the New UI -- the Unsupported
worklist row names the unclaimed class).
- Interaction picture is row-shaped: mouse and keyboard edit interactions,
commit timing (focus-loss autosave vs immediate-commit actions), context
menus, and how the slice behaves inside DataTree (indent, label,
expansion).
- "Before" evidence: the dialog screenshot harness does NOT apply (a slice
renders inside the DataTree), so the capture needs the live app -- which
means it is the DEVELOPER's to do while they explore (ask them to grab the
affected entry's rows and say where they put them). Only drive the app
yourself with their explicit go-ahead that it is closed and yours.

The analysis document keeps the four-section shape; section 4 (layout)
describes the row: label/value split, sizing, wrapping, and any multi-row
structure.

## Agreeing on how it works (gate)

Identical to convert-dialog: announce and STOP ("I've finished my analysis.
Are you ready to align our understanding?"), then point at the file and
correct round by round -- each round its own question and end of turn --
until the developer gives a clear negative to "any errors, gaps, or
questions?". Never summarize the document in chat.

## Deciding what to prove (gate)

Identical process (developer guidance -> `grill-with-docs` -> saved plan). Slice
plans must cover: compose (the field renders with correct values, not
Unsupported), edit -> ONE undo step, validation blocking, re-show after
external PropChanged, and cluster/bidi safety when the slice carries text.

## Planning the replacement (gate)

The route decision comes FIRST and is the developer's (present the tree
with a recommendation):

1. An existing `DetailFieldKind` fits -> the work is classification in
`EditorKindMap`; composer and `SliceFactory` already handle the rest.
2. A genuinely new interaction shape -> new `DetailFieldKind` + a new owned
`Fw*Field` control + a `SliceFactory` case.
3. A custom slice (`editor="Custom"`) -> an `ISlicePlugin` keyed by the
exact legacy `class=` string, registered in `SlicePluginRegistry`; no layout
edits.

Then map controls/patterns against the exemplar map exactly as convert-dialog
does when planning a replacement (including the no-exemplar catalog, package
search, `grill-with-docs` fill plan, and human-gated promotion row), and produce the
same four-section design report, with section 4 describing the proposed row
layout and every deliberate difference from the legacy slice.

The children-convert-first dependency gate applies here too: any dialog the
slice opens (choosers, create dialogs) must already have an Avalonia route
(converted, kit-covered, or FwMessageBox) before this slice proceeds. So
does the custom-control discipline: designing a new `Fw*Field` follows the
capability-comparison table with the stock/composed bias (convert-dialog's
custom-control sub-cycle), and the state-manifest + gate re-evaluation
resume rules are shared (`<SliceClass>-state.md`). At any gate, the same
choice applies: inform the developer and ask whether to convert the blocker
now in-session (launching the right skill with the class from context) or
pause.

## Building it (developer's choice)

**Scaffold** for a slice means: the editor string is classified (or the
plugin registered), a placeholder control composes and renders at the
slice's REAL position in the New UI detail view, tests compose green, and
legacy is untouched -- the row goes from "Unsupported" to "empty but
present". There is no per-slice launcher gate; the detail surface's UIMode
gate already covers it. Merge policy is the same as dialogs: scaffold is
branch-state only; nothing merges until Proving it works passes (an empty row
is worse than an honest Unsupported row for preview users).

**Implement** builds the control out from the design + test plan:

- Values project LCModel-free through `DetailValueFactory` /
`IDetailValueProvider` -- never a second projection of an existing recipe.
- Composition wires through `DetailComposer` (the field's
`FieldEditHandler` carries its edit operations).
- Edits stage through the edit context; the fenced session commits ONE undo
step; new edit operations go on a sub-capability interface (the
`IStructuredTextEditing` precedent) -- never widen `IDetailEditContext`.
- Idiom rules per `.claude/skills/fieldworks-avalonia-ui/references/style-system.md`;
WS typography via the multi-WS text exemplar when text is involved; a
null edit context yields read-only display.
- Compose-time snapshot discipline: rows do not live-update; the re-show
does. No ad-hoc refresh plumbing; refresh coordination stays with
`AvaloniaDetailRefreshController`.
- Plugin factories degrade: missing/null/throwing renders the labeled
Unsupported row, never a crash or a blank row.
- Keep `FwAvalonia` LCModel-free (projection and write-back live in
xWorks). The repository comment standard applies throughout.

## Proving it works

1. create-integration-test against the plan (tests land per the mirroring
rule: control tests in `FwAvaloniaTests/Detail/`, composer tests in
`xWorksTests/Avalonia/Composer/`).
2. Developer manual test in live FieldWorks, New UI on: the field at its
real position, edit interactions per the analysis document, focus-loss
autosave, single Ctrl+Z per save, cross-surface PropChanged refresh both
directions, tool-switch mid-edit settles cleanly.
3. Land the exemplar-promotion row for anything new (human-gated, same PR).
61 changes: 61 additions & 0 deletions .claude/skills/create-integration-test/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
name: create-integration-test
description: Turn a [class]-integration-test-plan.md into headless integration tests, one per plan item, each driving the scenario, asserting the outcome, and capturing a labeled snapshot. Use for TDD before implementation or as verification after it, whenever a test plan exists under Docs/migration/working/.
---

# Create Integration Test

Consumes the test plan a convert-* skill produced with the developer and
turns it into real tests, one plan item at a time. Plans exist for
dialogs, slices, AND owned controls (a control converted through the
custom-control sub-cycle gets its own plan under its own class name).

Input: the class name (or find the single plan when only one exists).
Plan location: `Docs/migration/working/<Class>/<Class>-integration-test-plan.md`.
If no plan exists, stop and say so -- the plan is authored with the
developer in the convert-* flow, never invented here.

## What each plan item becomes

One headless `[AvaloniaTest]` that:

1. **Drives** the scenario with the headless input pipeline (typing, focus,
commands) from a constructed dialog/control in the state the item names.
2. **Asserts** the behavioral outcome in code -- this is the pass/fail gate
(enabled state, staged value, validation message, payload content).
3. **Captures** a labeled snapshot as reviewable evidence
(`DialogSnapshot.Capture`, name `<Class>-NN-<kebab-label>` numbered in
plan order). Snapshots document; assertions gate.

Known headless limit: pointer hit-testing does not run headless. A plan item
that genuinely requires mouse interaction is implemented as far as the
model/keyboard path allows and flagged in the report as needing the manual
checkpoint.

## Where tests land

Derive the location from the SUT by the repository's test-mirroring rule
(tests mirror their SUT's project and subfolder):

- Dialog View/ViewModel (`Src/Common/FwAvaloniaDialogs/`, flat) ->
`FwAvaloniaDialogsTests/<Class>IntegrationTests.cs`
- Owned control in `Src/Common/FwAvaloniaDialogs/Controls/` (dialog
composite) -> `FwAvaloniaDialogsTests/Controls/`; owned control in
`Src/Common/FwAvalonia/` (shared) -> the `FwAvaloniaTests/` mirror of its
subfolder
- Launcher edge (`Src/LexText/LexTextControls/Avalonia/`) ->
`LexTextControlsTests/Avalonia/`
- Slice control (`Src/Common/FwAvalonia/Detail/`) ->
`FwAvaloniaTests/Detail/` (create the folder on first use)
- Composer wiring (`Src/xWorks/Avalonia/Composer/`) ->
`xWorksTests/Avalonia/Composer/`

## Process

Work the plan top to bottom, one item at a time: write the test, run it,
and record the result against the plan item (passing, failing-as-expected
for TDD, or blocked-needs-manual). Keep generated code to the repository
comment standard. When the plan is exhausted, run the owning suite in full
and report: items implemented, items flagged manual-only, suite counts, and
any plan item whose wording did not survive contact with the code (report
it back for the developer to re-decide -- do not silently reinterpret).
Loading
Loading