육안 검증 준비 — 전 페이지 렌더 + 제자리 갱신 E_SctMst 어서션 정정

[전 페이지 렌더] --db-render 가 첫 페이지만 뽑던 것을 전 페이지로 확장했다(이름_p1.png …).
운영 서식 128건이 다중 페이지라 첫 장만 봐서는 검증이 되지 않는다.

[E_SctMst 어서션 정정] --db-save-smoke 가 제자리 갱신 경로에서도 sctCount == walkerCount 를
요구하고 있었는데, 이 불변식은 버저닝 경로에만 성립한다.
제자리 갱신은 레거시와 동일하게 삭제된 컨트롤의 행을 지우지 않으므로(SctKey 안정성) 과거에
지워진 컨트롤의 고아 행이 누적된다. P347 에서 실제로 걸렸다 — E_SctMst 3행(MDesignerHost1,
TextBox1, TextBox2) 대 현재 XML 2개(MDesignerHost1, TextBox2)로, TextBox1 은 과거에 지워진
컨트롤의 잔존 행이었다. 기존 데이터이지 저장 경로의 결함이 아니다.
제자리 갱신은 "워커 산출 행이 전부 존재"(sctCount >= walkerCount)로 바꾸고 잔존 행 수를
리포트에 표시한다. 버저닝은 전량 재생성이므로 정확히 일치 요구를 유지한다.

[검증 준비 결과] 위험도 상위 16건을 SheetMe 로 재저장하고 저장 전/후 렌더를 픽셀 비교했다 —
39페이지 전부 동일(J209 6장, S256 7장 포함). 대상 선정은 운영 활성 디자인을 전수 스캔해
위험 요소로 가중치를 매겼다: 자리표시 15건 · Spread 7건 · Binary 569건(45%) ·
배경이미지 315건 · 다중페이지 128건 · 제자리갱신 36건.

레거시 뷰어 대조는 사용자가 직접 수행한다(공용 ServerInfo ini 의 CurrentServer 를 운영에서
테스트로 바꿔야 하는데, 그 파일을 레거시 EXE 187개가 공유하므로 자동화하지 않았다).
바탕화면 'SheetMe-검증패키지' 에 체크리스트·렌더 PNG 39장·자동검증 리포트를 준비했다.

검증: 테스트 70/70, edit-smoke 실패 0, 왕복 1,271건 diff 0/예외 0,
db-save-smoke 제자리 갱신(P163 정상/P347 잔존 1건 정상)·버저닝(S999) 양쪽 통과.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-12 08:57:26 +09:00
co-authored by Claude Fable 5
parent 71862c2986
commit d1e488625e
2 changed files with 46 additions and 18 deletions
+28 -14
View File
@@ -201,7 +201,11 @@ public partial class App : Application
}
}
/// <summary>DB 서식 첫 페이지 오프스크린 렌더 → PNG (Spread 격자 주입 경로 포함 검증)</summary>
/// <summary>
/// DB 서식 오프스크린 렌더 → PNG (Spread 격자 주입 경로 포함 검증).
/// 페이지가 여럿이면 <c>이름_p1.png</c>, <c>이름_p2.png</c> … 로 전부 뽑는다 —
/// 운영 서식 128건이 다중 페이지라 첫 장만 봐서는 검증이 되지 않는다.
/// </summary>
private static int RunDbRenderSmoke(string shtCod, string pngPath)
{
try
@@ -215,22 +219,32 @@ public partial class App : Application
}
var designer = new ViewModels.DesignerViewModel(document, dataBusiness.LoadSpreadGrids(shtCod));
var page = designer.Pages[0];
var directory = Path.GetDirectoryName(pngPath) ?? ".";
var stem = Path.GetFileNameWithoutExtension(pngPath);
var view = new PageView { DataContext = page };
var size = new Size(page.WidthDip, page.HeightDip);
view.Measure(size);
view.Arrange(new Rect(size));
view.UpdateLayout();
for (var i = 0; i < designer.Pages.Count; i++)
{
var page = designer.Pages[i];
var view = new PageView { DataContext = page };
var size = new Size(page.WidthDip, page.HeightDip);
view.Measure(size);
view.Arrange(new Rect(size));
view.UpdateLayout();
var bitmap = new RenderTargetBitmap(
(int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height), 96, 96, PixelFormats.Pbgra32);
bitmap.Render(view);
var bitmap = new RenderTargetBitmap(
(int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height), 96, 96, PixelFormats.Pbgra32);
bitmap.Render(view);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using var stream = File.Create(pngPath);
encoder.Save(stream);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
var target = designer.Pages.Count == 1
? pngPath
: Path.Combine(directory, $"{stem}_p{i + 1}.png");
using var stream = File.Create(target);
encoder.Save(stream);
}
Console.WriteLine($"{shtCod}: 페이지 {designer.Pages.Count} 렌더 완료");
return 0;
}
catch (Exception ex)