Skip to content

refactor(config): split grid-style editor VM into drafts (#118) - #179

Merged
mrcsin merged 1 commit into
masterfrom
grid-style-vm-split
Aug 6, 2026
Merged

mrcsin merged 1 commit into
masterfrom
grid-style-vm-split

Conversation

@mrcsin

@mrcsin mrcsin commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

The grid-style editor view model declared its ~77 style fields three times — property declarations, a Seed method, and a with-based BuildRecord. A field dropped from BuildRecord compiled fine and silently reverted on save. This is the fifth and final slice of the #118 debloat; it removes the last hand-maintained full-field list in the stack, so field omission stops being representable.

What changed

  • Nine draft classes, one per group record (DepthPaletteDraft serves both ReadOnlyCells and DisabledCells). A draft's property initializers are the seed (read from the group record); its Build() constructs the record positionally, so an omitted field is a compile error (CS7036), not a silent revert.
  • The parent VM shrinks to draft wiring — ten reactive draft properties, ReplaceDrafts (seed + swap the CanSave subscriptions on load), a BuildRecord of ten Build() calls + Orientation, and CanSave = the numeric-range checks only. SaveCommand, the load-failure path, and error routing are behavior-identical.
  • All 77 AXAML binding paths → grouped Group.Leaf form, compile-checked against the window x:DataType (a bad path fails the build, AVLN2000).
  • Validate removed from IGridStyleEditorFacade — with typed StyleColor a loaded record is valid by construction, so the seam is Load/Save only.
  • Architecture doc rewritten as current-state — the interim slice notes and the obsolete "Known gap" section are gone; the roadmap marks all five slices DONE.

Verification

  • dotnet build SemiStep.slnx — 0 warnings; dotnet test — 1727 passed, 0 failed; dotnet format clean.
  • The GridStyleEditorViewModel: ~60 fields maintained in three places; sync file I/O on the UI thread #118 thesis, proven — the guard-net non-vacuity scratch checks (recorded, reverted): drop a Build() argument → CS7036; mistype an AXAML path → AVLN2000; miswire a draft initializer → the per-draft round-trip test red; miswire a Build() slot → the perturbation guard red.
  • Coverage moved with the structure — nine per-draft round-trips (new <Draft>(fixture.Group).Build() == fixture.Group, DepthPaletteDraft against both palettes) replace the deleted seed guard; the perturbation guard pins the walked leaf count at 77 (asserted, not derived); the re-seed rewiring test proves the subscription swap.
  • Behaviour preserved — the untouched suites stay green: the Russian-culture malformed-hex end-to-end message, the owner-routing window tests over the renamed AXAML, SaveThenLoad_DistinctFixture, and GridStyleEditorWindowTests byte-identity. The on-disk YAML is unchanged.
  • Review chain: 5 comprehensive + 2 critical re-check + 2 final critical, all OUTCOME: ACHIEVED, no critical/major survived. Fixes: a DraftNumbers guard-dedup, the roadmap Slice-2 status corrected, two null-throw invariant tests, three draft-accessor style alignments, two comment trims.
  • Manual test (operator): confirmed.

Note: an unrelated GC-sensitive allocation probe (RecipeGridSurfaceContractTests.AppendStep_PerSurfaceTailAllocation…) flaked on one of three review runs — outside this branch's change surface. Re-run if CI trips it.

Closes #118

Per-task commits before collapse
79f094f docs(plan): record exec branch and verify steps
128ff2c docs(config): trim restatement in grid-style VM comments
1489a03 style(config): align grid-style draft accessors with VM convention
08d3a97 fix: address slice-5 review findings
db41dc8 docs(config): rewrite grid-style doc as current-state
da3342a refactor(config): split grid-style editor VM into per-group drafts
175ea33 feat(config): add grid-style editor per-group drafts
2c1e0f6 refactor(config): drop Validate from grid-style editor facade

🤖 Generated with Claude Code

The grid-style editor view model declared its ~77 style fields three
times over: property declarations, a Seed method, and a with-based
BuildRecord. A field dropped from BuildRecord compiled fine and silently
reverted on save. Slice 5 (the last of #118) replaces the monolith with
a thin parent plus one small ReactiveObject draft per group, where field
omission stops being representable.

- Nine draft classes, one per group record (DepthPaletteDraft serves both
  ReadOnlyCells and DisabledCells). A draft's property initializers are the
  seed, read from the group record; its Build() constructs the record
  positionally, so an omitted field is a compile error (CS7036), not a
  silent revert.
- The parent VM shrinks to draft wiring: ten reactive draft properties,
  ReplaceDrafts (seed + swap the CanSave subscriptions on load), a
  BuildRecord of ten Build() calls plus Orientation, and CanSave as the
  numeric-range checks only. SaveCommand, the load failure path, and error
  routing are behavior-identical.
- All 77 AXAML binding paths become grouped Group.Leaf form, compile-checked
  against the window x:DataType (a bad path fails the build, AVLN2000).
- Validate is removed from IGridStyleEditorFacade: with typed StyleColor a
  loaded record is valid by construction, so the seam is Load/Save only.
- The architecture doc is rewritten as current-state (the interim slice
  notes and the obsolete "Known gap" section are gone).

The guard net moves with the structure: per-draft round-trips catch a
wrong-source seed or a wrong Build slot, and the perturbation guard pins
the walked leaf count at 77. A dropped field is now CS7036 or AVLN2000 and
a miswired one is a red test, proven by the non-vacuity scratch checks.

The editor is behavior-preserving and the on-disk YAML is unchanged. This
is the final slice: the last hand-maintained full-field list in the
grid-style stack is gone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mrcsin
mrcsin marked this pull request as ready for review August 6, 2026 12:08
@mrcsin
mrcsin merged commit 21f6929 into master Aug 6, 2026
1 check passed
@mrcsin
mrcsin deleted the grid-style-vm-split branch August 6, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GridStyleEditorViewModel: ~60 fields maintained in three places; sync file I/O on the UI thread

1 participant