Skip to content

test(config): add grid-style silent-drop guards - #175

Merged
mrcsin merged 1 commit into
masterfrom
grid-style-guards
Aug 5, 2026
Merged

mrcsin merged 1 commit into
masterfrom
grid-style-guards

Conversation

@mrcsin

@mrcsin mrcsin commented Aug 5, 2026

Copy link
Copy Markdown
Member

Problem

The grid-style editor (GridStyleEditorViewModel) maintains ~80 style fields in three parallel blocks — property declarations, Seed, and BuildRecord — sitting 200+ lines apart in a 523-line file. A field surfaced in Seed but missing from BuildRecord's _source with { … } compiles fine and silently reverts on save, with no compile or test guard. Issue #118 will rewrite exactly these blocks (nest the flat record, type colors, split the view model), which is the highest-risk moment for re-introducing a silent drop. This lands the anti-regression net first.

What changed (tests only — no production change)

Three directional guards, split by direction and field kind so each catches what the others structurally cannot, all driven by one distinct-value fixture (GridStyleOptionsTestData.Distinct() — 77 unique, valid, in-range fields):

Guard Catches
Seed-populates a dropped/cross-wired Seed line — including the nullable (decimal?/FontFamily) and italic fields a naive round-trip is blind to
Perturbation (exact-one-field) a dropped/mis-targeted BuildRecord line — a plain BuildRecord(Seed(x)) == x round-trip cannot (with keeps _source, which is the seed source)
Save→load (via facade) a GridStyleDtoMapper drop / GridStyleMapper mis-wire — the flatten/unflatten layer the nest slice rewrites

A count == 77 assert guards the reflection filter against drift.

Why three guards, not one: the existing round-trip test seeds Default (32 identical #000000 colors, masks cross-wires) and structurally cannot fail on a dropped BuildRecord line, nor on a dropped Seed line for the 14 nullable-fallback fields (null → BuildRecord restores _source). The three directional guards close all of that.

Verification

  • dotnet build SemiStep.slnx — 0 warnings; dotnet test — 1687 passed, 0 failed; dotnet format clean.
  • The guards are proven non-vacuous by scratch checks (delete a line, confirm the matching test goes red, revert):
    • drop a BuildRecord line (InfoColor) → perturbation test red, names the field;
    • drop a nullable Seed line (ValidationPanelMaxHeight) → Seed-populates red (0 vs 150.5);
    • drop an italic Seed line → red (false vs true);
    • drop a GridStyleDtoMapper line (CellWeight) → save→load red (loaded 400 vs fixture 800).
  • Review chain: comprehensive (5 agents) → smells → comment audit → critical, all clean after fixes. The reviews caught a real hole — the fixture's CellFontWeight: 400 equalled Default, and since that DTO field maps ?? default, a dropped mapper line would substitute 400 and leave the save→load guard green; changed to 800, and two reviewers independently re-verified all 78 fields now differ from Default.
  • One residual, documented: a bool↔bool Seed cross-wire among the five all-true italics is inherently undetectable with a two-valued type — lower-probability than a dropped line.

This net unblocks the #118 debloat (slices 2–5: async Save, nest the record, type colors as StyleColor, split the view model into per-group drafts). #118 stays open.

Per-task commits before collapse
3638d1f docs(plan): record exec branch and verify steps for grid-style guards
96050d2 docs(test): trim restating comments in grid-style guards
547d222 test(config): name the surfaced-property count and fix Perturb weight derivation
2c8eeb4 test(config): fix fixture default-collision and trim redundant guards
373c6e0 test(config): add grid-style BuildRecord perturbation guard
471c4d2 test(config): add grid-style distinct fixture and value round-trip guards

🤖 Generated with Claude Code

The grid-style editor maintains ~80 style fields in three parallel blocks
(property declarations, Seed, BuildRecord). A field surfaced in Seed but
missing from BuildRecord's `_source with { … }` compiles fine and silently
reverts on save, with no compile or test guard. Issue #118 will rewrite
exactly these blocks (nest the record, type colors, split the view model),
so land the anti-regression net first.

Add three directional guards, split by direction and field kind so each
catches what the others structurally cannot, driven by one distinct-value
fixture (77 unique, valid fields):

- Seed-populates: after seeding, assert every surfaced property equals the
  fixture -- catches a dropped or cross-wired Seed line, including the
  nullable and italic fields a naive round-trip is blind to.
- Perturbation (exact-one-field): change each property from its seeded
  value, assert BuildRecord changed in exactly that property's mapped
  field -- catches a dropped or mis-targeted BuildRecord line. A plain
  round-trip cannot: `with` keeps _source, which is the seed source.
- Save->load: round-trip the fixture through the facade -- catches a
  GridStyleDtoMapper drop / GridStyleMapper mis-wire (the flatten/unflatten
  layer the nest slice rewrites).

A count assert (77) guards the reflection filter against drift. Each guard
is proven non-vacuous by scratch checks (delete a line, confirm the
matching test goes red, revert). The one residual -- a bool-to-bool Seed
cross-wire among the five italics -- is inherent to a two-valued type and
documented.

Tests only; no production change. This net unblocks the #118 debloat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mrcsin
mrcsin marked this pull request as ready for review August 5, 2026 12:21
@mrcsin
mrcsin merged commit db4ea02 into master Aug 5, 2026
1 check passed
@mrcsin
mrcsin deleted the grid-style-guards branch August 5, 2026 12:23
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.

1 participant