Commit Graph

615 Commits (ecb2b9f7b127560681e50cf36564eeca4a553e85)

Author SHA1 Message Date
RyuJongJin ecb2b9f7b1 modular_sync #6 RemoteFs (F11): 원격 4종의 mkdirs 를 한 규칙으로 (remoteMkdirs) - 같은 이름의 파일이면 모두 RemoteNameIsFile
- remote_fs.dart: remoteMkdirs(client, rel, mkdirOne) - 없는 위 폴더까지 · 이미 폴더면 그대로 · 같은 이름의 파일이면 RemoteNameIsFile (파일은 그대로).
  서버마다 다른 것은 한 칸 만들기뿐 (FTP MKD · SFTP mkdir (그 사이 다른 곳이 만들었으면 그대로) · SMB 채널 · WebDAV MKCOL).
  위 폴더 계산 remoteParent 하나 (FTP · SFTP · SMB 의 _parent 복사 3벌 지움)
- 고치기 전 판 (bdea662) 에서 FTP 는 같은 이름의 파일 위 mkdirs 가 오류 없이 넘어감을 확인 (r6_before.log) - 뒤의 쓰기가 엉뚱한 오류로 끝났다.
  WebDAV 는 서버 오류 글, SFTP · SMB 는 서버마다 다른 예외였다
- 약속 시험: 실제 시험 서버 WebDAV (TestDavServer) · FTP (pyftpdlib) · SFTP (asyncssh). SMB 는 Android 에서만 (기기 확인)

사용자가 보게 될 동작: 원격으로 복사 · 맞출 때 받는 쪽에 같은 이름의 파일이 있으면 서버와 상관없이 "같은 이름의 파일이 있어 폴더를 만들 수 없습니다"

확인: analyze 0 · 단위 1489 ×2 · 통합 6/6 ×2 · base10 214장 0px · windows_ftp_shot · windows_sshkey_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:27:13 +09:00
RyuJongJin bdea662daa modular_sync #3 OptionText: "rsync 옵션이 있나" 를 popt 규칙 하나로 (rsyncHasOption) - 거르기 값의 u 를 -u 로 오인하던 것 (데이터)
- rsync_options.dart rsyncHasOption(words, short, long): 짧은 묶음은 한 글자씩, 값 자리 (값을 받는 글자 B e f M T @ 의 뒤 ·
  값을 받는 긴 옵션의 다음 낱말) 는 옵션으로 보지 않음. rsyncShortWithArg 는 거르기 해석 (rsync_filter) 과 함께 씀
- "-u 가 있나" 세 곳 (transfer_job._update · withUpdateOption · optionsUpdate) 이 이것을 부름. 예전에는 "-로 시작하는 낱말에 u 가 있으면"
  이라 -f'- build/' · -f "- run/" 를 -u 로 읽었다: 미리 보기는 "받는 쪽이 더 새것은 건너뜀", 실제 rsync 는 덮어씀 · 앱이 맞출 때도 건너뜀
- 고치기 전 판 (512d290) 에서 같은 시험이 틀리게 나옴을 먼저 확인: 판단 [true, true, true] (기대 [true, false, false]) ·
  실제 rsync 는 -avf'- build/' 에서 build.txt 를 보내는데 앱은 -u 로 봄 (c3_before.log). 고친 판에서는 2회 통과
- 약속 시험: 판단 표 + 실제 rsync (받는 쪽이 더 새 파일, 옵션 5가지) - 앱의 -u 판단 = rsync 가 보내는지

사용자가 보게 될 동작: rsync 옵션의 거르기 값에 u 가 들어 있어도 "받는 쪽이 더 새것은 건너뜀" 으로 잘못 보거나 앱이 맞출 때 건너뛰지 않음 (실제 rsync 와 같게)

확인: analyze 0 · 단위 1486 ×2 · 통합 6/6 ×2 · base10 214장 0px · rsync_page ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 12:39:19 +09:00
RyuJongJin 512d2904d2 modular_sync #4 CopyPolicy: "받는 쪽이 더 새것이면 건너뛰기" 판단을 SameFile.keepNewer 하나로
- SameFile.keepNewer(skipNewer, targetModified, modified): 설정 (229) 이 켜져 있고 받는 쪽이 2초 넘게 새것일 때만 그대로 둠, 시각을 모르면 덮음
- 부르는 곳: 폴더 합치기 (로컬 isNewerThere · 원격 anyCopy) · 압축 풀기 덮어쓰기 (archive_ops). 같은 이름 창의 "더 새것" 표시 (name_clash) 도
  SameFile.targetNewer - 2초 규칙을 따로 계산하던 곳이 없어짐 (robocopy 는 /XO, rsync 는 -u 로 같은 일)
- 동작은 그대로 (판단 모으기만). 약속 시험 한 줄 더함

확인: analyze 0 · 단위 1484 ×2 (c4_unit1 · c4_unit3) · 통합 6/6 ×2 · base10 214장 0px · move_left_shot · check_shot ×2
(c4_unit2 에서 ftp_test 1 · l10n_check 1 이 같은 때 실패 - 따로 3회 · 전체 다시 1회 모두 통과, 부하 때의 흔들림으로 보이며 따로 보고)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 11:58:58 +09:00
RyuJongJin 81a2c169ff modular_sync F1: 맞추기는 로컬 · 원격 모두 같은 구현 하나 (anyMirror) - 로컬도 거르기 · 같은 이름 폴더 충돌을 따름
- FileOps.mirror 가 늘 anyMirror 를 부름. localMirror (거르기를 무시 · 같은 이름 폴더 충돌 (M1) 을 모름) 를 지움
- anyMirror 의 같은 파일 판단: SameFile.forAppSync(remote: 경로에 원격이 있는지, move: strict) - "받는 쪽이 더 새것도 같음" 은 원격일 때만
  (로컬끼리는 크기 + ±2초 그대로)
- 약속 시험: mirror_one_impl (실제 폴더 - 거르기: 거른 것은 보내지 않고 받는 쪽의 거른 것은 지우지 않음 · 나머지는 --delete, 미리 보기와 같음 /
  같은 이름 폴더: 지우기 없으면 건너뛰고 알림 · 있으면 파일로). same_file 의 원격 경우는 실제 WebDAV 시험 서버로

사용자가 보게 될 동작: 로컬끼리 맞추기 (현재 방식 · 실시간 동기화) 가 rsync 옵션의 거르기를 따름 - 미리 보기에서 빠진 것은 실제로도 보내지 않고
받는 쪽의 거른 것은 지우지 않음 (예전에는 미리 보기와 달리 다 보내고 다 지웠다). 받는 쪽의 같은 이름 폴더는 지우기 포함일 때만 바꿈

확인: analyze 0 · 단위 1484 ×2 · 통합 6/6 ×2 · base10 214장 0px · rsync_page · copy_sync_shot · lsync_p0_shot · live_excl_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 11:02:48 +09:00
RyuJongJin 9d1883311f modular_sync F5: 화면에 보이는 실행 옵션 글 = 실제 실행 인수 (runOptionsText 하나)
- core/sync_preview.dart runOptionsText: 실행 인수 (rsyncArgs · robocopyRuns) 와 같은 규칙 - 원본 지우기 옵션은 빼고 이동일 때만 그 방법의 것,
  robocopy 는 앱이 붙이는 것 (이동의 /MOVE /IS /IT /IM · 링크 /XJ · 더 새것 건너뛰기 /XO) 까지
- 부르는 곳: 모니터링 "실제 실행" · 실행 전 미리 보기 (effectiveRunText) · 탐색기 복사 · 이동 확인 창 · 실시간 동기화 [최종 정리] 창
- 고친 어긋남 (15 검토 F5): 탐색기 확인 창이 robocopy 이동을 /MOVE 로만 보였다 · [최종 정리] 창이 모니터링에서 고친 옵션이 있어도 늘 -avHPOg 로 보였다
- 약속 시험: 보이는 글 = 실제 인수 (robocopy 4 · rsync 4 · 현재 방식)

사용자가 보게 될 동작: 탐색기의 robocopy 이동 확인 창에 실제 옵션이 모두 보임 · [최종 정리] 창에 실제로 실행할 옵션이 보임

확인: analyze 0 · 단위 1482 ×2 · 통합 6/6 ×2 · base10 214장 0px · lsync_p0_shot ×2 · rsync_page ×2
(rsync_page 1회는 시작 3초 만에 시험 앱이 끝남 - media_kit 디버그 기록 파일의 PID 겹침, 이 고침과 무관 · 따로 보고)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:15:30 +09:00
RyuJongJin 88f0701d23 modular_sync F2: "같은 파일" 판단을 SameFile 하나로 - 실행 전 미리 보기 = 실제 맞추기
- lib/core/files/same_file.dart: 크기 + 바뀐 때 ±2초, 받는 쪽 시각이 올린 때인 곳 (원격이 낀 앱 맞추기, 이동 아님) 은 받는 쪽이 더 새것도 같음.
  SameFile.forAppSync(remote, move) · targetNewer
- 부르는 곳: 로컬 맞추기 (local_transfer) · 원격 맞추기 (any_transfer) · 미리 보기 (sync_preview) · 실시간 동기화 기다림 (sync_diff) ·
  -u 건너뛰기 · 폴더 합칠 때 더 새것 지키기
- 고친 어긋남 (15 검토 F2): 원격으로 앱이 직접 맞출 때 받는 쪽이 같은 크기에 더 새 파일이면 미리 보기에 "바뀜" 으로 나왔는데 실제로는
  보내지 않았다. 이제 미리 보기도 실제와 같은 판단 (rsync_runner viaDav · sync_preview_view direct 가 SameFile.forAppSync 를 넘김)
- 약속 시험: 판단 표 + 실제 파일로 미리 보기와 실제 맞추기 (anyMirror · localMirror) 가 같은지 - 원격 규칙 · 이동 · 로컬

사용자가 보게 될 동작: 원격으로 앱이 직접 맞출 때 받는 쪽의 같은 크기 · 더 새 파일이 미리 보기에서 빠짐 (실제로도 보내지 않던 것). 로컬 · rsync · 이동은 그대로

확인: analyze 0 · 단위 1479 ×2 · 통합 6/6 ×2 · base10 214장 0px · rsync_page · copy_sync_shot · lsync_p0_shot · live_excl_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:27:39 +09:00
RyuJongJin e89a0ff2d7 보기 화면: 키만 받는 Focus 감싸개는 접근성 노드를 만들지 않음 - 'node.built' assert 고침 (28 지적 10/20)
- 장을 손으로 넘긴 뒤 [사진 정보] 창을 닫아 포커스가 보기 화면으로 돌아올 때, 화면 전체를 감싼 Focus 의 접근성 노드가 바뀌며
  디버그 판에서 Flutter 접근성 assert ('node.built', rendering/object.dart) 가 났다 (rc2 에서도 같음)
- 갈라 보기: 장 넘기기 + 창 둘 다 있어야 남 · 그림 내용 · 아래 막대 · ColorFiltered 를 빼도 남 · 이 Focus 를 빼면 사라짐
- 고침: includeSemantics: false (키 받기 · autofocus 는 그대로, 화면 읽기 프로그램이 읽을 단추 · 그림은 안쪽에 그대로)

확인: analyze 0 · reader_dialog_semantics 2/2 ×2 (예전 늘 실패) · windows_reader_shot ×2 · 단위 1475 ×2 · 통합 6/6 ×2 · base10 214장 0px

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 08:40:51 +09:00
RyuJongJin 051c259d89 app_controller 509 → 498줄: 자막 파일 고르기 · 다른 이름 저장 · 편집할 수 있는지를 SubtitleFiles 로
- SubtitleFiles.pickFor (있는 경로 건너뜀 · 이름으로 언어, 더한 수) · saveAs (SRT 바이트 · 표현 못 한 글자 수) · canEdit (static)
- app_controller 는 부르기만 (알림 · 기록은 그대로)
- 약속 시험: 실제 파일 · 실제 SRT 바이트, 고르기 · 저장 창 대신 정한 것을 돌려주는 저장소 (사용자가 고른 것)

확인: analyze 0 · 단위 1475 ×2 · 통합 6/6 ×2 · base10 214장 0px

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 07:46:32 +09:00
RyuJongJin 093cf3252e translate 시험 2개: 좁은 도구 막대에서는 [더 보기] 메뉴로 누른다 (예전부터의 실패, rc2 에서도)
- 시험 창의 브라우저 화면이 804 너비라 도구 막대가 좁은 꼴 (640 미만) - 번역 · 작업 현황 단추가 [더 보기] 메뉴 안에 있어
  툴팁으로 찾던 시험이 실패했다. 앱 쪽 문제 아님 (관리자 10/24: 시험 쪽이면 기대값 그대로, 메뉴를 열어 누름)
- tapToolbar: 넓으면 그 단추, 좁으면 도구 막대 안의 [더 보기] → 같은 항목. 고른 결과는 메뉴가 닫힌 뒤 들어오므로
  (번역이 도는 동안 그리기가 느림) 메뉴가 닫힐 때까지 기다림

확인: analyze 0 · translate_split 1 ×2 · web_translate 1 ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 06:08:55 +09:00
RyuJongJin b9b23e9122 browser_real 시험: 좁은 도구 막대에서도 동영상 감지를 본다 (예전부터의 실패, rc2 에서도)
- 시험 창의 브라우저 화면이 804 너비라 도구 막대가 좁은 꼴 (640 미만) - [다운로드] 가 글 없는 아이콘 단추라 '다운로드' 글로 찾던 시험이
  감지와 상관없이 실패했다. 앱의 동동영상 감지는 제대로 됨 (RESULT true)
- 감지는 넓든 좁든 같은 알림 글로 본다 (찾았으면 '다운로드', 못 찾았으면 '다운로드 (… 찾지 못했지만 …)'). 누르기도 알림 글로

확인: analyze 0 · browser_real 1 ×2 (동영상 감지 true · 쿠키 내보내기 · yt-dlp 읽기)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:55:55 +09:00
RyuJongJin f9d4257c0d 통합 시험 4개: E6 (Windows 처음 모양 TC) 뒤로 실패하던 것 - X-plore 를 직접 고르고, TC 로 쓰는 화면은 TC 단계를 더함
- windows_b6_input · rsync_page: 시험이 X-plore 모양을 직접 고름 (TC 는 폴더를 [이름], 파일은 이름 · 확장자를 다른 칸에 보여 이름 글을 찾지 못했다)
- windows_move_left_shot · windows_rsync_narrow_shot: X-plore 시험은 그대로 두고, Total Commander 모양으로 같은 일을 보는 단계를 더함
  (관리자 10/24: 사용자가 TC 로 쓰므로). move_left TC: [D] 고르기 → F6 이동 → 알림 → Enter 로 원본 D 에 들어가 남은 것만.
  rsync_narrow TC: [sub] · [rsub] 고르기 → 좌 → 우 확인 창. 캡처 이름은 …_tc_…

확인: analyze 0 · b6_input 2 ×2 · move_left 12 ×2 · rsync_narrow 12 ×2 · rsync_page 3 ×3
(rsync_page 1회째는 시작 4초 만에 시험 앱이 끝나 did not complete - 시험 논리와 무관, 그 뒤 3회 모두 통과)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:49:46 +09:00
RyuJongJin 8b8cb23fb9 단일 실행: 멈춘 첫 창이면 약 3초 안에 "응답 없음" 을 묻는다 (예전 약 33초)
- 첫 창에 넘겨 본 결과를 셋으로: 받음 · 아직 준비 안 됨 (instance.json 없음 · 연결 안 됨) · 연결은 됐는데 답 없음
- 답 없음은 1초씩 3번이면 바로 unresponsive (관리자 결정 10/24). 첫 창이 정상이면 그 창에 넘기는 동작 · 막 뜨는 중이면
  잠깐 다시 해 보는 동작은 그대로
- 약속 시험: 받기만 하고 답하지 않는 실제 소켓 - 5초 안에 unresponsive

확인: analyze 0 · 단위 1474 ×2 · player_test 17 ×2 · 통합 6/6 ×2 (a · c) · base10 214장 0px
(b 회차는 시험 도중 C: 임시 폴더의 시험 폴더 jj_usechk_fixed_412 와 시험 휴지통 폴더가 통째로 없어져 412 23장 벗어남 - 이 고침과 무관, 원인 미확인)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:23:00 +09:00
RyuJongJin eaaa096ea1 (가) 10곳: 시험이 앱 동작을 바꾸던 길을 주입 · 모듈로 (lib 의 @visibleForTesting 은 들여다보기 4곳만 남음)
- Tor: debugRunning · executable 없앰 → 떠난 뒤 잠시 켜 두기를 IdleStop 모듈로 (schedule · cancel · stopNow).
  환경 설정 > Tor 는 IdleStop 을 받음 (처음 값 = 앱의 Tor), [지금 끄기] = stopNow
- Wi-Fi 공유: debugLoopbackOnly · debugAddresses · loopbackOnly 인자 없앰 → WifiShareNet 주입 (열 주소 · 설정 열기).
  WifiSharePage(net:) 가 debugLaunch 를 대신함. debugFail 없앰 - 시험이 실제 다른 루프백 주소 (127.0.0.x) 에서 틀린 코드를 보냄
- 관리자 권한: Elevation.debugElevated 없앰 → PlatformInfo.elevated (조립 주입), CefView(elevated:)
- CEF 시작 시간: 바꿀 수 없게 (const) - 시험은 가짜 시간을 넘김
- 단일 실행: debugStopListening 없앰 - 시험이 instance.json 을 아무도 듣지 않는 포트로 (받는 곳이 죽은 첫 창)
- SMB 찾기: 전역 debugFindSmbServers 없앰 → PlatformServices.findLanSmb 주입
- 남은 @visibleForTesting (들여다보기만): browser_page · tor_page debugNav, secret_store dpapiAt, reader_page dropMissingFiles

확인: analyze 0 · 단위 1473 ×2 · 통합 6/6 ×2 · base10 214장 0px · windows_wifi_shot ×2 · windows_smbfind_shot ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 01:06:00 +09:00
RyuJongJin 512c9d8b14 M2-b: Windows 휴지통 주입 (전역 recycleBinForTest 없앰)
- recycle_bin: RecycleBinBackend 약속 + WindowsRecycleBin (이 기기의 휴지통). 전역 recycleBinForTest · recycle() · restoreRecycled() 없앰
- delete_ops: deletePaths(bin:) · undoRecycle(bin:) - 처음 값 WindowsRecycleBin
- ExplorerDevice.recycleBin → ExplorerFlows · ExplorerDeleteFlow(recycleBin:)
- 시험: useTestRecycleBin(device) 가 시험 기기에 시험 폴더 안의 휴지통을 넣음. 영구 삭제만 하는 약속 시험 4개는
  휴지통으로 보내면 실패하는 것을 넘김 (사용자 휴지통에 닿지 않게). 넘겨받은 휴지통 약속 시험 1개 더함
- 시험용 휴지통: 자기 폴더가 없어졌으면 다시 만들지 않고 그대로 알림 (진단)
- 전부터 있던 실패 2개 고침 (E6 부터 Windows 처음 모양이 Total Commander 라 이름 · 확장자가 다른 칸):
  windows_check_shot_test · windows_b3_shot_test 가 X-plore 모양을 직접 고름

확인: analyze 0 · 단위 1472 ×2 · 통합 6/6 ×2 · base10 214장 0px · windows_check_shot ×2 · windows_b3_shot ×2
(첫 확인의 통합 1회에서 412 지우기가 '경로를 찾을 수 없음' 으로 11장 벗어남 - 다시 4회 모두 0px, 원인 미확인)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 00:22:23 +09:00
RyuJongJin beb8107d81 M2-a: LocalFs (목록 · 저장 장치 · 드라이브) 주입 + 빈 목록 경합 고침
- lib/app/local_fs.dart: LocalFs 약속 (list · volumes · probe), RealLocalFs = 이 기기 그대로
- ExplorerDevice.listVolumes/probeDrive → ExplorerDevice.fs (LocalFs)
- ExplorerController(fs:) → loadDir(list:) (처음 값 listEntries)
- 빈 목록 경합: reloadOpen 이 끝날 때, 시작할 때 읽어 둔 것 중 닫힌 것만 잊음
  (예전: 시작할 때 찍은 열린 목록으로 지워, 다시 읽는 동안 펼친 폴더가 비어 보였다)
- 결정적 시험 explorer_reload_race_test: 다시 읽기를 붙잡는 느린 LocalFs 를 생성자로 넘김
  (실제 폴더 · 실제 목록). 예전 판에서는 실패 (펼친 폴더 [] ), 고친 판에서는 통과

확인: analyze 0 · 단위 1471 ×2 · 통합 6/6 ×2 · base10 214장 0px

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 21:43:25 +09:00
RyuJongJin 3434ad4937 M1-2: lib 의 …ForTest 이름 정리 (실제 기능 · 주입으로)
- SuRoot.resetForTest → forgetGrant (이번 실행의 su 허락 잊기)
- ComGuard.releaseForTest → release (ensure 와 짝인 CoUninitialize)
- debugUpscalerForTest 전역 → PlatformServices.createUpscaler 주입
- 원격 썸네일 reset…ForTest 3개 → forgetRemoteThumbHub · forgetRemoteRangeSupport · forgetRemoteThumbNet
- vaultIterationsForTest 전역 → VaultPage(iterations:) (처음 값 VaultCrypto.defaultIterations)
- 남은 recycleBinForTest 는 M2 (TrashBackend) 에서 정리

확인: analyze 0 · 단위 1470 ×2 · 통합 6/6 ×2 · base10 214장 0px · com_guard_test · windows_vault_shot_test ×2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 20:45:32 +09:00
RyuJongJin 2199d7c15f M1-1: "Android 인 척" 스위치 · 실패 흉내 플래그를 주입으로 (PlatformInfo · WebViewProxyTarget)
- MemorySecretStore.failRead/failWrite 를 없앰 → 시험 쪽 test/support/flaky_secret_store.dart
- WebProxy.debugAndroid/debugSetProxy 를 없앰 → WebViewProxyTarget 주입 (Android=ProxyController, 그 밖=없음)
- ExitGuard.forceAndroid 를 없앰 → PlatformServices.platform (PlatformInfo)
- JJ_NLLB_LOW_MEMORY 환경 변수를 없앰 → NllbTranslator(lowMemory:), 처음 값은 PlatformInfo.host
- archive_ops · rsync_launch · file_error 의 기본값을 PlatformInfo.host 로 모음
- 이름 바꿈: WebProxy.shownForTest → shown, debugReset → reset
- 보안: 남은 Tor 웹 뷰가 있는 동안에도 removeImplicitRules (localhost 까지 Tor 로)
- 약속 시험 platform_info_contract_test 3개

확인: analyze 0 · 단위 1470 ×2 · 통합 6/6 ×2 · base10 214장 0px

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 20:05:31 +09:00
RyuJongJin 39d81f1a73 M0: 안전 저장소를 못 읽으면 마스터 잠금을 '알 수 없음' 으로 - 문을 열지 않고 마스터를 덮어쓰지 않는다
사용자가 보게 될 동작: 기기 안전 저장소를 읽지 못하면 저장된 비밀번호를 쓰는 기능이 열리지 않고, 환경 설정 > 보안에
까닭과 [다시 읽기] 가 보인다. 다시 읽히면 평소대로 마스터를 묻는다.

- 예전: 읽지 못하면 빈 것으로 보아 마스터가 없는 것처럼 문 (SecretGate) 이 열렸고, 그 상태에서 마스터를 정하면 진짜 값을 덮어쓸 수 있었다
- MasterLock.storeUnreadable: load 가 예외 대신 표시 (앱은 켜짐). ensure 는 한 번 다시 읽고 못 읽으면 false.
  setMaster · setSuper · clearMaster · clearSuper · setAsk 는 MasterStoreUnreadable. reload()
- 보안 설정: 까닭 · [다시 읽기] (정하기 · 바꾸기 · 끄기 숨김). 보관함 [마스터로도 열기] 는 까닭을 알림
- 비밀번호 다시 저장 [다시 시도] 가 되면 마스터 잠금도 다시 읽음. settings_store 의 TODO(M0) 지움
- 약속 시험 master_store_unreadable_test 4 (읽기가 실제로 실패하는 저장소를 시험 파일 안에 - lib 흉내 플래그 쓰지 않음)
- 확인: 단위 1467 ×2 · 통합 6/6 ×2 · 캡처 214장 base10 과 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 19:26:02 +09:00
RyuJongJin 6f9d8f6284 목록에서 두 번 누르면 도로 나오던 것 고침 · TC Enter = 열기
- 원인 (실제 앱): 목록 줄 (TC · '폴더 + 파일 목록') 의 폴더 · '..' 는 한 번에 열려, 두 번 누르면 두 번째 누르기가 같은 자리의 '..' 에
  맞아 도로 나왔다
- TC 모양: 폴더 · '..' 도 한 번 = 고르기, 두 번 = 열기 (ClickPolicy doubleOpens - Total Commander 와 같게)
- TC 모양: Enter = 열기 (폴더는 들어가기, 파일은 열기) - 바꿀 수 있는 키 동작 'open', 처음 키는 TC 모양일 때만 Enter
- '폴더 + 파일 목록': 한 번 열기는 그대로, 연 직후 두 번 누르기 시간 (300ms) 안의 다음 누르기는 버림 (마지막 틀 시각으로 잼)
- 약속 시험: 누르기 표 (TC) · TC 한 번 / Enter / '..' 두 번 · 목록 배치 곧바로 두 번째 누르기 · 시간 지난 '..' 한 번
- 점검 시험: TC 를 두 번 누르기 · Enter 로 되돌림 (실제 시간에서 들어가기 · 나오기 됨), 목록 배치 단계 더함 - 214장 2회 같음 (base10)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:48:45 +09:00
RyuJongJin afe15620bd E6 보충 (관리자 결정 10/23): 지운 뒤 초점 · 좁은 TC 줄의 확장자 · TC 전용 점검 단계
- 지운 뒤 초점: 지운 줄의 다음 줄로, 마지막이었으면 앞 줄로 (TC · X-plore 같음) - focus_after_delete (순수 함수, 약속 시험 4) +
  지우기 흐름이 부름. 실제 화면 시험: TC 목록에서 F8 단추로 지우면 다음 줄이 지금 줄
- TC: 확장자 칸이 없으면 (좁은 줄 · 좁아 숨긴 열) 이름에 확장자를 붙인다 ('notes.txt') - 정보를 숨기지 않게.
  기존 큰 글자 시험 3곳의 TC 기대를 'a' → 'a.txt' 로 (이 결정에 따른 것, 주석에 적음)
- 탐색기 점검 시험: TC 전용 단계 (Backspace 로 맨 위 · 메뉴 [열기] 로 들어가기 · Backspace 로 나오기 · F5 · F6 · F8 · 지운 뒤 초점,
  단계마다 폴더 시각 다시 고정 + Ctrl+R). 두 번 누르기는 이 실제 시간 시험에서 열기로 잡히지 않아 단위 약속 시험이 본다
- 확인: 단위 1461 ×2 · 통합 6/6 ×2 · 캡처 201장 2회 0px 같음 (base9) · X-plore 는 '삭제 확인' 3장만 바뀜 (초점)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:30:21 +09:00
RyuJongJin ae3365bff1 E6 2 · 3: Total Commander 모양 (창마다 목록 · '..' · 아래 F3~F8 · 남은 공간) · 좁은 창의 줄 모양 (공용 줄 부품)
- TC 모양: 트리 대신 지금 폴더의 목록 (paneListRows - '폴더 + 파일 목록' 의 목록과 같은 함수, 목록의 스크롤).
  사용자가 고른 '폴더 + 파일 목록' 배치 · Rsync 화면은 그대로 트리
- tc_key_bar: F3 보기 · F4 편집 · F5 복사 · F6 이동 · F7 새 폴더 · F8 삭제 - 이미 있는 동작을 부름
- tc_drive_space: 창 위 남은 공간 / 전체 - ExplorerDevice.diskSpace 로 받음 (시험은 TestExplorerDevice.space)
- 좁은 창 (창 폭 200 아래, narrowRowWidth): 아이콘 칸 줄임 · 끌기 손잡이 숨김 · 열 대신 이름 먼저 (크기 · 날짜는
  두 줄이 들어가는 줄 높이에서 이름 아래 - TC 26 은 이름만) · 열 머리도 이름만. X-plore · TC 가 같은 ExplorerRowView
- 약속 시험 explorer_tc_look_test 4개. 점검 시험은 X-plore · TC 두 모양을 찍는다 (폴더 시각 · 남은 공간 고정)
- 확인: 단위 1456 ×2 · 통합 6/6 ×2 · 캡처 180장 2회 정확히 같음 (base8) · X-plore 1920 · 960 은 base7 과 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 07:48:42 +09:00
RyuJongJin 20f9d083b2 E6 1: 탐색기 모양 처음 값을 기기마다 (Windows = Total Commander) · 예전 판이 저장한 X-plore 는 한 번만 묻기
- ExplorerSettings: 처음 값 defaultStyle (Windows totalcmd · Android xplore). 예전 파일에 모양 키가 없으면 그때의 X-plore.
  Windows 에서 저장된 xplore 이고 물었다는 표시 (explorerStyleV2) 가 없으면 styleAskPending (저장 안 함)
- style_ask: 탐색기를 열 때 한 번 [바꾸기] (Total Commander) / [그대로] (X-plore) - 창 밖으로 닫지 못함, 어느 쪽이든 다시 묻지 않음.
  환경 설정에서 직접 고르면 묻지 않음
- 약속 시험 explorer_style_contract_test: 새 설치 · 저장된 xplore (키 없던 예전 파일 포함) · windows/totalcmd 안 물음 · [그대로] · [바꾸기]
- X-plore 모양 (트리) 을 보는 기존 시험 14개 파일 + 공용 하네스에 style = 'xplore' 를 밝힘 (기대값 그대로, 관리자 승인 10/23)
- 설정 JSON 골든: 새 키 explorerStyleV2 한 줄 · 처음 값 출력의 Windows 모양 totalcmd 만 바꿈. 사전 4개 (en · ja · zh-Hans)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 05:39:39 +09:00
RyuJongJin 8c561a6133 알림 시간을 시험 전용 길이 대신 주입으로: NoticeTiming (InheritedWidget, 없으면 appNoticeDuration 10초)
- lib/ui/notice.dart 의 noticeDurationForTest 를 지움 (lib 에 시험 전용 길이를 두지 않음 - 관리자 10/23)
- 탐색기 점검 시험은 MaterialApp 을 NoticeTiming 으로 감싼다. 약속 시험: 감싸면 그 시간, 없으면 10초
- 확인: 캡처 2회 90/90 같음 · 앞 판 (5303663) 과도 90/90 같음 → base7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 04:53:09 +09:00
RyuJongJin 53036633d3 알림 시간 주입: 시험이 알림 시간을 정할 수 있게 (앱은 그대로 10초 - U2)
- notice.dart: appNoticeDuration (10초, 앱의 값) · noticeDuration (읽기) · noticeDurationForTest (시험만, @visibleForTesting)
- 탐색기 점검 시험: 알림이 실제 시간으로 닫히지 않게 두고, 정한 자리 (복사 알림은 선택을 끈 뒤 · 휴지통 알림은 이동을
  누르기 전) 에서 닫는다 - 찍는 때와 10초가 겹쳐 장면 14 · 27 이 실행마다 달라지던 것
- 확인: 같은 판 2회 90/90 픽셀까지 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 04:42:59 +09:00
RyuJongJin e3f8d8dbef app_actions 나누기 (720 → 119): 위쪽 막대 · 화면 이동 · 밀어서 옮기기 · 사용량 · 화면 배율을 lib/ui/app_bar/ 모듈로
- app_actions.dart 는 AppActions (설정 · 종료 버튼) 만 두고 옮긴 것을 그대로 내보낸다 (부르는 곳 그대로)
- 약속 시험: AppNavButtons.homeId · isCompact

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 03:41:35 +09:00
RyuJongJin 3b3d70fc18 tor_page 나누기 (740 → 499): 웹 뷰 부분 (tor_web_view) · 안내 (tor_messages) 를 lib/ui/tor/ 모듈로
- 웹 뷰가 화면 상태의 _clearProfile 을 직접 부르던 것을 인자 (clearProfile) 로 - 모듈이 화면에 기대지 않게
- 약속은 tor_test 의 torAddress · torBrowserArguments · torWebRtcBlockScript · TorViewHost 시험이 본다 (20 통과)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 03:36:12 +09:00
RyuJongJin 3b3ce6386e live_sync 나누기 (692 → 465): 맞출 것 계산 (SyncDiff) · rsync 찾기와 인수 (SyncCommands) 를 lib/app/sync/ 모듈로
- LiveSync.diff → SyncDiff.of, LiveSync.rsyncArgsFor · robocopyArgsFor → SyncCommands.rsyncArgs · robocopyArgs (시험 5곳 고침)
- 약속 시험: SyncDiff.of (보낼 것 · 지울 것 · 거르기 · 한도 · 바꾸지 않음)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 03:31:47 +09:00
RyuJongJin db38d0ddbf batch_test 나누기 (971 → 361 + 536): 화면 시험은 batch_ui_test, 대역은 support/batch_doubles
- 시험 수 그대로 (나누기 전 29 = 나눈 뒤 29), 기대값 그대로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 03:26:56 +09:00
RyuJongJin 49745c0d52 main.dart 나누기 (939 → 236): 시작 단계를 lib/startup/ 모듈로, 앱 위젯은 ui/app_root
- Windows · Android 가 복사해 쓰던 시작 단계 (startCore) 와 다운로드 연결 (createDownloads) 을 하나로 - 차례는 그대로
- Windows 끝내기 (WindowsQuit) · 실행 요청 처리 (handleLaunchRequest) · Android 시작 · 두 번째 창 · 도우미
- main.dart 는 옮긴 공개 이름을 그대로 내보낸다 (시험 · 다른 곳)
- 약속 시험: createDownloads · lastWorkText

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 02:58:19 +09:00
RyuJongJin 1689221019 home_page 나누기 (1566 → 190): 위쪽 막대 · 인코딩 막대 · MKV 목록 · 자세히 · 자막 줄 · 작업 기록 · 이동을 lib/ui/home/ 모듈로
- 화면 조각은 공개 위젯 (key 받음), 일은 AppController 가 · 화면은 부르기만
- 약속 시험: LogPanel · LogStrip · JobStatusIcon

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 02:26:10 +09:00
RyuJongJin 5de4412dc2 app_controller 나누기 (1672 → 506): 일은 lib/app/controller/ 모듈이 하고 화면 상태는 잇기만
- 작업 대기열 (JobQueue) · 작업 기록 (AppLog) · 목록 공유 (VideoListShare) · 편집 목록 (VideoList)
- 동영상 분석 (VideoProbe) · 파일 옮기기 (VideoFiles) · 자막 파일 (SubtitleFiles) · 인터넷 자막 (SubtitleDownload)
- AI 자막 · 자막 번역 (AiSubtitleRunner) · MKV 묶음 (MkvBatch) · 인코딩 고르기 (EncodeChoice) · 재생 준비 (PlaybackPrep)
- 실행 중 설정 · 켤 때 정리 · 다운로드 드라이브 (app_runtime), AiOptions
- 공개 이름은 그대로 (화면 · 시험이 부르는 것), 같은 번역 줄 만들기 두 곳은 하나로
- 약속 시험: JobQueue · AppLog · EncodeChoice · VideoListShare · VideoFiles · VideoList

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 01:56:07 +09:00
RyuJongJin aea1ec5eba vault_page_test 흔들림 고침 (기대값 그대로): 기다림을 실제 시간으로 · 보관함 쓰기가 다 끝날 때까지
- 원인: until 이 횟수 (200번) 로 끊겨 부하 때 일이 덜 끝난 채 넘어갔고, 끝맺음의 '.tmp 없음' 한 번 확인이 목록 저장과
  빈 폴더 목록 저장 사이에 맞아 folders.jjd.tmp 쓰기가 연 채 남아 임시 폴더를 지우지 못했다 (errno 32, 6/18 재현)
- until: 최대 60초 실제 시간, 안 되면 그 자리에서 실패 (조용히 넘어가지 않음). vaultQuiet: .tmp 없음이 10번 잇달아일 때
- 확인: 6개 동시 × 3회 18/18, 혼자 10회 연속 통과

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 01:36:54 +09:00
RyuJongJin 8eaa83b69d ai_upscale_ui 나누기 (659 → 387): 준비 (upscale_prep) · 비교 보기 (upscale_compare) 를 모듈로
- 약속 시험: upscaleOptionsOf · readerPageFile (그림 파일 · ZIP 안의 그림)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:56:57 +09:00
RyuJongJin 7d724ee9ca browser_test 나누기 (646 → 165 + 419): 화면 시험은 browser_page_test, 대역은 support/browser_doubles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:52:30 +09:00
RyuJongJin d031584e7a browser_page 나누기 2: DNS 덮개 · 페이지 번역 · 도구 막대 · 안내 줄 · 브라우저 동작 · 엔진 고르기를 모듈로 (2006 → 483줄)
- dns_block (DnsBlockWatch · DnsBlockCover), page_translation (PageTranslation), browser_toolbar, browser_banners,
  browser_actions (Tor 안내 · 쿠키 지우기 · 페이지 다운로드), cef_view 의 browserEngineView
- 화면은 상태만 갖고 모듈을 부른다. 약속 시험: PageTranslation · DnsBlockWatch

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:51:06 +09:00
RyuJongJin ad9a12fbe1 browser_page 나누기 1: 웹 엔진 (Edge · Chrome) · 즐겨찾기 막대 · 패널 · WebNav 를 lib/ui/browser/ 모듈로
- 로그인 쿠키 파일 쓰기 (Edge · Chrome 이 따로 하던 것) 를 writeLoginCookies 하나로
- 살려 둔 웹뷰 · Chrome 시작 제한 시간은 그 모듈이 갖는다 (CefView.startTimeout)
- 약속 시험: NavWatch · writeLoginCookies · deleteExportedCookies

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:45:07 +09:00
RyuJongJin d83b0b5aef 설정 A: 일반 분야 (GeneralSettings) · 남은 키 정리 - toJson · fromJson 은 분야 목록만 돈다
- 일반: 즐겨찾기 · 저장 공간 정리 · 바뀐 기본값 알림 · 안쪽 → 바깥 · 비밀번호 기억 · 휴지통 · 모든 파일 안내 (allFilesHint2)
- imageExts 는 보기 화면 분야 (ReaderSettings) 로
- 표시 cookieScopeV2 → 다운로드, robocopyLinksV1 → 복사 분야로
- AppSettings 에 남은 것: 분야 목록 · 모르는 항목 보존 · 비밀 값 빼기 · 바뀐 기본값 알림 · 실행 중 값 (webViewDataDir)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:15:58 +09:00
RyuJongJin e828227693 설정 A: 재생 분야 (PlaybackSettings) - 동영상 열기 · 재생 목록 · 외부 플레이어 · 자막 크기 · 기본 자막 언어
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:12:48 +09:00
RyuJongJin 7fe2f0562f 설정 A: MKV · 자막 분야 (MkvSettings) - 저장 위치 · 이동 버튼 · 인코딩 · AI 자막 · OpenSubtitles 키를 분야로
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:11:13 +09:00
RyuJongJin c5aa8c657b 설정 A 분야 13: 화면 · 앱 모양 (DisplaySettings) - 키 13 · clampUiScale → DisplaySettings.clampScale
- ComponentManifest 의 자기 필드 components 는 그대로 (같은 이름이라 잘못 바뀐 것을 되돌림)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:06:30 +09:00
RyuJongJin 8d26d1af1e 설정 A 분야 12: 원격 서버 (RemoteSettings) - WebDAV · SFTP · SMB · FTP 목록 · 쉬는 시간 · WebDAV 외부 열기, 키 7
- 비밀 값 처리 (webdavServers 의 plainSecrets · 새 비밀 값은 평문으로 쓰지 않음) 그대로, 설명 주석도 함께 옮김

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:37:49 +09:00
RyuJongJin 828d978812 설정 A 분야 11: 탐색기 도구 (ExplorerToolSettings) - 시스템 폴더 · 루트 · Wi-Fi 공유 · ZIP 수준, 키 6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:32:25 +09:00
RyuJongJin a35293271e 설정 A 분야 10: 암호 보관함 (VaultSettings) - 키 3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:30:18 +09:00
RyuJongJin 056ca186d9 설정 A 분야 9: 실행 · 종료 · 업데이트 (RunSettings) - 키 11 · backgroundRun 함께
- 도구 고침: setter 안의 '      closeAction = v' 줄을 선언으로 잡던 것 (타입은 글자로 시작 · 첫 선언만)
- 문서 주석 [AppSettings.run.x] → [RunSettings.x]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:28:09 +09:00
RyuJongJin 7c6320165a 설정 A 분야 8: 웹 브라우저 (BrowserSettings) - 키 10
- 이미 옮긴 분야 뒤의 같은 이름 (s.tor.homeUrl) 은 바꾸지 않음
- browser_page 의 _CefView 자기 필드 cefWhenElevated 는 그대로 (같은 이름이라 잘못 바뀐 것을 되돌림)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:23:30 +09:00
RyuJongJin 6beeb22e43 설정 A 분야 7: 다운로드 · YouTube (DownloadSettings) - 키 12
- settings_group.dart 에 pickEnum (분야들의 읽기가 같이 씀 - fromJson 의 지역 함수 pick 대신)
- AppSettings.resolvedDownloadRoot 는 download.root 를 씀

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:20:58 +09:00
RyuJongJin 6054daf17a 설정 A 분야 6: 보기 화면 (ReaderSettings) - 키 9 · zipComicV2 표시
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:16:46 +09:00
RyuJongJin 506803ca65 설정 A 분야 5: AI 그림 · 해상도 올리기 (AiImageSettings) - 키 27 · aiServices 의 비밀 값 처리 (plainSecrets) 그대로
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:14:56 +09:00
RyuJongJin 059c8cba59 설정 A 분야 4: 복사 · 이동 · rsync · 실시간 동기화 (CopySettings) - 키 16 · 도우미 _method 함께
- 부르는 곳: s.copyTasks → s.copy.tasks 꼴 (RsyncRun 의 자기 필드 copySkipNewer 는 그대로 - 같은 이름이라 잘못 바뀐 것을 되돌림)
- 문서 주석 [AppSettings.x] → [CopySettings.x] 등

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:10:42 +09:00
RyuJongJin ee7524e1c7 설정 A 분야 3: Tor 브라우저 (TorBrowserSettings) - 키 5 · defaultTorHome → TorBrowserSettings.defaultHome
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 22:43:02 +09:00