# ShellTidy 0.0.2 검증 기록

## 환경과 방법

- Windows 11 x64 개발 PC, Visual Studio 2026 Insiders, MSVC 14.52.37025.
- Windows SDK 10.0.26100.0 / C++20 / Release x64 / `/O2 /MT /W4`.
- `tools/test.ps1`, `tools/build.ps1 -Test`: 테스트별 백업은 `tools/output`에 생성.
- 격리 테스트는 배포용 EXE와 분리된 `ShellTidy.Tests.exe`에서만 실행. 배포용 EXE에는 `--self-test`가 없음.
- 로컬 검증은 `tools/runtime`의 Python·Node·Git과 `tools/toolchain`의 MSVC·SDK로 실행.
- 테스트 등록은 `HKCU\Software\ShellTidy\Tests\Run-<PID>` 아래에서 생성하고 정리.
- 실제 사용자 앱 등록 삭제 및 실제 Explorer 종료 테스트는 수행하지 않음.

## 자동 검증 범위

- 따옴표, 환경 변수, `%1` 인수, 모호한 미존재 경로, 잘못된 문자열 데이터.
- Picvium의 현재/과거 경로 구분과 JPG·PNG·WebP·PDF·PSD 참조 그룹화.
- UserChoice 기본 앱 보호와 해당 등록 삭제 차단.
- MarkText 및 Obsidian의 실제 참조/Applications 키 삭제와 복원.
- 하드코딩하지 않은 확장자 발견, 다른 Markdown 편집기 참조 보존.
- MRUList 정합성 및 기존 유형/바이트 복원.
- 공유 ProgID·CLSID, 앱 실행 파일 및 나중에 추가된 무관한 값 보존.
- 바이너리 값 백업, 반복 복원, 복원 충돌 건너뛰기.
- 일부 실패, 변경 도중 값 갱신, 백업 실패 차단, 취소, 접근 거부.
- 손상 백업 체크섬, 조작된 UserChoice 복원 대상 거부.
- 공유 WOW64 분기의 중복 억제와 백업의 명시적 32비트 뷰 보존.
- ExplorerCommand 조회 전용 표시와 COM 핸들러 참조만 삭제.
- 열 정렬의 자연수·대소문자·한국어 비교 기준.
- HKCU Capabilities 65개를 32/64비트 양쪽에서 발견하더라도 물리 등록 65개만 한 번씩 삭제/복원.
- 긴 팝업 본문의 크기/줄 수 제한, 음수 좌표의 모니터 중앙 배치와 작업 영역 경계 보정.
- 동일 사용자/세션 중복 실행 잠금과 마지막 핸들 종료 시 잠금 해제.

정확한 실행 개수와 결과는 `tools/output/test-results.txt`에 생성됩니다.
GitHub Actions에서는 `build/test-results.txt`를 CI 산출물로 보관합니다.
자동 테스트가 통과해도 아래 수동 확인까지 통과했다고 의미하지 않습니다.

최종 자동 테스트 결과: **118 passed, 0 failed** (2026-10-27, 로컬 MSVC 테스트 빌드).
로컬 검증은 C 드라이브의 MSBuild 대신 `tools/build.ps1`의 로컬 MSVC로 수행했습니다.
GitHub Actions는 `ShellTidy.vcxproj`로 Release EXE와 `/p:SelfTest=true` 테스트 EXE를 각각 빌드하고
격리 테스트를 실행합니다.

## 0.0.2 2차 검토: 기본 앱 판별, 상태 판정, 사용 안 함, UI

1차 검토 이후 다음 문제를 확인하고 수정했습니다. 36개 검증을 추가했습니다.

- **Windows 11 기본 앱 기록 방식:** 개발 PC를 읽기 전용으로 확인한 결과, FileExts의 확장자 키 가운데
  153개에 `UserChoiceLatest\ProgId`가 있고 79개는 `UserChoice`와 다른 ProgID를 가리켰습니다.
  기존 코드는 `UserChoice`만 읽어 Picvium.Image.jpg 같은 실제 기본 앱을 보호하지 못했습니다.
  이제 `UserChoice`, `UserChoiceLatest\ProgId`, `AssocQueryStringW(ASSOCSTR_PROGID)`,
  `UrlAssociations`를 모두 보호 근거로 사용합니다. 수정 후 같은 PC에서 해당 등록이 보호됨을 확인했습니다.
- **연결되지 않은 드라이브:** 없는 드라이브 경로는 `ERROR_PATH_NOT_FOUND`를 반환하므로
  '경로 없음'으로 분류되었습니다. 이제 볼륨 루트에 접근할 수 있을 때만 '경로 없음'으로 판정합니다.
- **숨겨진 체크 항목:** 검색·필터로 보이지 않는 체크 항목도 삭제되던 문제를 고쳤습니다.
  현재 목록에 보이는 체크 항목만 처리하고, 제외한 개수를 확인 창에 표시합니다.
- **등록 없음 상태:** 참조하는 ProgID·Applications 키·CLSID가 없으면 '등록 없음'으로 표시합니다.
  Applications 키가 없더라도 App Paths로 실행 파일을 찾으면 그 파일로 판정합니다.
- **따옴표 없는 공백 경로:** CreateProcess와 같은 순서로 해석하여, 실행 가능한 후보가 하나도 없으면
  '경로 없음'으로 판정합니다.
- **기본 앱 확인 실패:** 한 확장자의 기본 앱 정보를 읽지 못하면 그 확장자와 관련된 항목만 보호합니다.
  연결 등록 루트를 열거하지 못하는 경우에는 이전처럼 전체를 보호합니다.
- **WOW64 뷰 불일치:** 같은 공유 등록이 다른 뷰에서 정상이면 '경로 없음' 대신 확인 필요로 표시합니다.
- **표시 정보:** `@리소스` 메뉴 이름과 `&` 단축키 표시를 해석하고, CLSID 이름과 파일 설명·회사를 표시합니다.
- **사용 안 함 / 사용:** verb의 `LegacyDisable` 값과 `Shell Extensions\Blocked`의 CLSID 값을
  추가·제거합니다. 생성한 값은 백업에 "이전 값 없음"으로 기록하고, 복원할 때 같은 값일 때만 제거합니다.
  핵심 verb와 기본 앱 verb는 잠그고, 위조된 저널은 저장 단계에서 거부합니다.
- **기타:** UAC 경로의 중복 검색 제거, 배포용 EXE에서 자체 테스트 분리, 복원이 끝난 백업 정리.

실제 사용자 레지스트리의 **읽기 전용 검색**을 수정 후 다시 실행했습니다. 2,941개 항목,
읽기 경고 0개, 기본 앱 확인 실패 0개, 등록 없음 18개, 경로 없음 0개, 사용 안 함 35개였습니다.
같은 PC에서 첫 실행은 약 5.7초, 캐시가 채워진 뒤에는 약 1.7초였습니다(1차 검토 때는 약 1.27초).
추가 시간은 기본 앱 조회와 파일 버전 정보 읽기에서 생깁니다. 이 검사에서 레지스트리 값을 쓰거나
삭제하지 않았으며, 보고서에는 집계만 기록했습니다.

## 0.0.2 코드 검토 및 회귀 검증

기존 50개에 다음 오류와 경계 조건을 다루는 32개 검증을 추가했습니다(1차 검토, 82개).

- 폴더명 속 `.exe`, `.com` 명령의 `.exe` 인수, 잘못 닫힌 따옴표, 드라이브/루트 상대 경로,
  한글 미존재 경로, 과도한 환경 변수 확장 및 0바이트 레지스트리 값.
- 선택 이후 및 백업 이후 참조 실행 명령 변경 시 삭제 차단, 실제 변경 여부 전달,
  완료/복원된 저널의 반복 삭제 방지.
- 백업 v2의 실행 명령 정보 저장과 실제 v1 형식 고정 데이터의 복원 호환성.
- 빈 값/하위 키 스냅샷, 잘못된 MRUList 변경의 저장·복원 거부와 하위 키 충돌 상세 정보.
- 빈 SubCommands·ExtendedSubCommandsKey·DelegateExecute 및 Applications 내부의 최신 메뉴 보호.
- 삭제된 키의 기존 상위 키에만 쓰기 제한을 설정한 격리 ACL 권한 검사. 실제 UAC는 호출하지 않음.
- 디렉터리를 실행 파일로 오판하지 않는 상태 표시, SystemFileAssociations 메뉴의 검색·삭제·복원,
  해석할 수 없는 기본 앱 메타데이터에 대한 삭제 보호.

실제 사용자 레지스트리의 **읽기 전용 검색**도 별도로 실행했습니다. 2,941개 항목,
읽기 경고 0개, 기본 앱 확인 실패 0개, 약 1.27초였습니다. 이 수치는 해당 개발 PC의 한 번의
실행 결과이며 다른 PC의 성능을 보장하지 않습니다. 보고서에는 앱명/경로 대신 집계만 기록했고,
이 검사에서 레지스트리 값을 쓰거나 삭제하지 않았습니다.

명령 재검증은 작업 시작 시 재검색하고, 개별 변경 직전에 원본 값/하위 키를 비교합니다.
다른 프로그램의 레지스트리 변경까지 하나의 트랜잭션으로 잠그지는 않습니다.
새 백업은 v2이며 v1은 계속 복원할 수 있습니다. 복원 상태를 갱신한 v1 파일도 v2로 저장되므로
해당 파일은 0.0.1에서 다시 열 수 없습니다.

검토 시 [Microsoft의 WOW64 공유/리디렉션 표](https://learn.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys),
[환경 변수 확장 버퍼 규칙](https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-expandenvironmentstringsw),
[레지스트리 값 읽기 규칙](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw)을 확인했습니다.
목록 중심 조작은 [ShellExView의 기능 안내](https://www.nirsoft.net/utils/shexview.html)를 참고했습니다.
[PowerToys 공개 저장소](https://github.com/microsoft/PowerToys)도 확인했으며 외부 구현 코드를 복사하거나
런타임 의존성을 추가하지 않았습니다.

## UI 확인

README와 소개 페이지의 UI 이미지는 사용자의 요청에 따라 가상 앱/경로를 넣어 재구성했습니다.
이 미리보기는 실제 사용자 설치 목록을 사용하지 않으며, 실기 검증 증거로 간주하지 않습니다.

2차 검토에서 UI를 메뉴 막대·도구 모음·필터·가상 목록·하단 정보 창·상태 표시줄 구조로 다시 작성했습니다.
개발 PC(150% 배율)에서 창을 화면 밖으로 옮겨 캡처하는 방식으로 첫 화면 배치, 문제 항목 우선 정렬,
행 색상, 상태 표시줄 집계, 선택 행에 따른 정보 창 갱신과 삭제 버튼 활성화를 확인했습니다.
캡처에는 실제 설치 목록이 보이므로 저장소에 올리지 않았습니다. 창 메시지로 흉내 낸 클릭은
ListView의 드래그 감지와 맞지 않아 체크박스 클릭 검증에 사용할 수 없었습니다.
마우스 체크박스 조작을 포함한 실제 UI 조작은 아래 수동 확인 항목처럼 사용자가 확인했습니다.

실제 Windows 11에서 시작, 실제 등록 목록 표시, 한국어 컨트롤과 상세 정보 영역을 확인했습니다.
사용자의 드래그 끊김 제보 후 부모의 `WS_CLIPCHILDREN`, 자식의 `WS_CLIPSIBLINGS`,
무효 영역만 그리기를 적용했습니다. 수정 후 화면 자동화는 사용자 Escape 입력으로 중단되어
실제 드래그 재검증과 전체 DPI 화면 검수는 남아 있습니다.

사용자가 제공한 팝업 잘림 화면에 따라 긴 확장 목록을 제거하고, 스크롤 없는 짧은 요약과
대상/오류 전체 복사 버튼으로 구성했습니다. 시작 창은 커서가 있는 모니터 작업 영역의 중앙에
배치하며, 화면 경계를 벗어나는 크기는 제한합니다. 기하·본문 제한 자동 테스트는 통과했으며
최종 화면의 시각 검수는 사용자 직접 확인 대상으로 남아 있습니다.

## 실제 사용 오류 회귀

사용자의 기존 백업을 수정하지 않고 읽어 확인한 결과, 131개 변경 계획 가운데 물리 대상은
66개였고 65개가 32/64비트 뷰에서 중복되었습니다. 완료 단계는 66개, 미실행 단계는 65개로,
중복 대상을 다시 삭제하려다 `ERROR_RETRY (1237)`가 표시된 경우였습니다.

HKCU의 공유 분기와 리디렉션되는 Classes/CLSID 분기를 구분하고, 검색 그룹 및 삭제 계획에서
공유 물리 대상을 정규화했습니다. 65개 Capabilities를 실제 생성·삭제·복원하는 격리 회귀
테스트와 양쪽 뷰의 중복 선택 테스트로 검증했습니다. 이전 백업의 형식은 그대로 지원합니다.

## 수동 확인 항목

2026-10-27에 사용자가 Windows 11 개발 PC에서 0.0.2 릴리스 EXE
(SHA256 `f2114a1d60fbd4e1f8d78e0eae8cb3ad8c041d1044e84473a542f2eb697455a0`)를 직접 사용해
**Windows 10 관련 항목을 제외하고 문제없이 동작한다**고 확인했습니다. 아래 표의 "사용자 확인"은
이 실사용 확인을 뜻하며, 항목별 측정 기록이나 자동 테스트를 대신하지 않습니다.

| 시나리오 | 확인할 결과 | 현재 상태 |
|---|---|---|
| 체크박스·키보드 | 마우스 클릭과 Space로 체크, 보호 항목 체크박스 숨김, Del/F7/F8/F5/Ctrl+F/A/C/S | 사용자 확인 (Windows 11) |
| 메뉴·도구 모음 | 메뉴 활성/비활성, 백업 목록 팝업, 보기 옵션, 행 우클릭 메뉴 | 사용자 확인 (Windows 11) |
| 속성·외부 열기 | 속성 창, 레지스트리 편집기에서 열기(LastKey), 파일 위치 열기, txt/csv 보고서 | 사용자 확인 (Windows 11) |
| 사용 안 함 실제 반영 | LegacyDisable verb와 Blocked CLSID가 실제 Explorer 메뉴에서 숨겨지고 사용으로 복귀 | 격리 테스트 통과, 사용자 확인 (Windows 11) |
| 중복 실행 | 새 창 없이 기존 창/모달 활성화 | 잠금 자동 테스트 통과, 사용자 확인 (Windows 11) |
| 시작 위치·팝업 | 화면 중앙, 스크롤 없는 요약과 상세 복사 | 기하/본문 제한 테스트 통과, 사용자 확인 (Windows 11) |
| 열 머리글 연속 클릭 | 오름/내림 전환, 정렬 화살표, 체크/선택 상태 유지 | 사용자 확인 (Windows 11) |
| 창 이동/크기 변경 | 텍스트 손상·중복 그리기 및 끊김 없음 | 사용자 확인 (Windows 11) |
| DPI | 컨트롤 겹침과 텍스트 잘림 없음 | 사용 배율(150%)의 캡처와 사용자 확인. 다른 배율은 사용자 환경 밖 |
| Explorer 자동 재시작 | 기본 체크 해제, 성공 시만 통지·선택 재시작·검색 갱신 | 사용자 확인 (Windows 11) |
| Explorer 재실행 실패 | 비승격 재실행 재시도와 별도 복구 감시 | 코드 검토. 실패를 일부러 일으키는 시나리오는 미실행 |
| UAC 수락/취소 | 같은 계정에서 작업, 취소 시 등록 보존 | 사용자 확인 (Windows 11) |
| Windows 10 | 검색·삭제·복원 및 네이티브 UI | **미검증** |

Explorer 재시작에는 [Restart Manager](https://learn.microsoft.com/windows/win32/rstmgr/functions)를
우선 사용하고, 대체 종료에서도 실행 파일·사용자 SID·세션·프로세스 시작 시각으로
확인한 Explorer 프로세스만 다룹니다. 직접 실행과 복구 감시는 비승격 토큰을 사용합니다.
Windows 사용자 세션의 실제 파일 작업을 중단할 수 있어 자동 테스트에서는 호출하지 않습니다.
