# 10 · 결정 기록 (Decision Record) > 확정 사항의 단일 원천. 변경은 과거 행을 지우지 않고 **새 행으로 정정**(규칙 = [16 §2-5](16-doc-git-conventions.md)). 큰 결정(대안 비교)은 ADR 문서로 두고 여기 §2에 색인한다. > 번호는 한 줄로 늘어난다(DR-n). 조사·이식 항목의 접두 ID(`SET-`·`LIC-`…)는 [docs/port](port/00-index.md) 소관. ## 1. DR 표 | # | 일자 | 결정 | 근거 · 출처 | | --- | --- | --- | --- | | DR-1 | 10-03 | **올 러스트 · 3-OS 단일 코드.** 창/입력 = `winit 0.30` + `softbuffer 0.4`(Linux Wayland/X11 dlopen) · 그리기 = `nexa-gfx` CPU 래스터 · 컨트롤 = `nexa-ctl`. 관리 런타임·UI 프레임워크·OS 네이티브 컨트롤 금지(macOS 메뉴바도 창 안 자체 그리기 — nexa-sql과 같음) | 사용자 지시 "OS 간 차이 최소화 · 전부 직접 개발" · nexa-sql 골격([port/40](port/40-sql-app-skeleton.md) SKEL-001~) · dir2 DR-1 계승 | | DR-2 | 10-03 | **컨트롤은 전부 nexa-ui.** dir2 앱 안 컨트롤(`ctl/` 16종)·`nexa-gui/widgets`(rows·dock·pathbar·menubar·tabbar·chrome·overlaybar)는 nexa-ui로 승격하거나 기존 nexa-ctl 컨트롤로 대체. 앱 크레이트에 범용 컨트롤 금지. nexa-ui 공개 API는 **추가만**(nexa-sql 빌드 유지 · 바꿔야 하면 nexa-sql도 같은 묶음에서) | 사용자 지시 · [port/51 §4](port/51-ui-controls.md)(UIK-201~222 추가 후보) · nexa-ui DR-2(앱 도메인 의존 0) | | DR-3 | 10-03 | **설정 구조 = nexa-sql `nsql-settings` 차용.** `REGISTRY: &[Entry]` 단일 원천 · `settings.conf`(nexa-conf · 변경분만 · 원자 저장) · 곁 표(`OS_DEFAULTS`·`DEPENDS`·`HIDDEN`·`ADVANCED`·`INFO_KEYS`·`RENAMED`·`RESCALED`·`OLD_DEFAULTS`) · 설정 창은 레지스트리에서 생성(검색·트리·카드·Advanced·JSON). **키 이름 = nexa-sql 규칙(`<접두>.<이름>`) · 값·기본값·페이지 구성 = dir2 계승**(예 `ui.theme = dark`). 세션 상태는 `session.conf`로 분리(`Store` + `SaveScheduler`). dir2 `settings.cfg`는 첫 실행에 1회 가져오기(`migrate::import_dir2`) | 사용자 지시 "설정 구조는 nexa-sql 차용" · [port/41 §5](port/41-sql-settings.md) SET-001~137 · [port/31 §5](port/31-catalog-settings-i18n.md) 대응표 | | DR-4 | 10-03 | **라이선스 = nexa-license(Ed25519 · `nxl1`) · 정책 = dir2 계승.** 전 기능 무료 · 상업 사용은 라이선스 필요(P1~P8) · 기능 게이트 0(`license.gates` HIDDEN 자리만) · 제품 id **`nexa-dir`**(dir2와 같은 제품) · 파일 `nexa-dir.license` · 폴더 `<설정 폴더>/license` → 기기 공용 폴더 · `ndir-license` = `nsql-license` 복제. dir2 X-15의 P-256/CNG 계획은 **폐기**(크로스플랫폼 불가). 진입점 = Help ▸ 라이선스… + About 상태 줄(상태줄 배지는 보류 — dir2 배치 유지) | 사용자 지시 · [port/42 §4·§5](port/42-sql-license.md) LIC-151~197 · dir2 `LICENSE.md` | | DR-5 | 10-03 | **OS 분기는 `nexa-dir/src/platform/` 한 층.** 포트(trait) = `Shell`(기본 셸 탐지) · `Pty` · `ContextMenuProvider` · `Trash` · `FileClipboard` · `DragSource` · `Watcher` · `Opener` · `MachineId`(nexa-license 내장). 운영 = `windows.rs`/`macos.rs`/`linux.rs` · 시험 = `fake.rs`. 다른 OS·미지원 = `None`/`Err(Unsupported)` → 호출부가 안내. 기본 셸: Windows `pwsh` → `powershell` → `cmd` · macOS/Linux `$SHELL` → `/bin/zsh`(mac) → `/bin/sh` | 사용자 지시(터미널 셸 OS 분기) · [port/40 §5-7](port/40-sql-app-skeleton.md) SKEL-425~432 · [port/44](port/44-sql-ci-test-docs.md) CI-103 | | DR-6 | 10-03 | **크레이트 접두 `ndir-*`** · 앱 bin **`nexa-dir`**(exe 이름 = 제품명) · **버전 `0.23.0`**부터(dir2 `0.22.0`의 다음 · 제품 연속 · 발급 라이선스 `max_major 0` 호환). 버전 자리 = 루트 `Cargo.toml` 하나 | nexa-ui `nexa-*`와 이름 충돌 회피 · nexa-sql `nsql-*` 선례 · [port/42](port/42-sql-license.md) LIC-152·177 | | DR-7 | 10-03 | **플러그인 ABI = dir2 바이트 호환**(export `memory`·`nx_meta`·`nx_preview`·`nx_archive` · import `env` 7종 · 버퍼 규약 · 격리 수치). 동봉 `markdown.wasm`·`archive.wasm`은 **무수정 로드**가 회귀 기준. 탐색 경로(관리 설치본 → 드롭인 → 동봉)·매니페스트·sha256·3-OS 빌드 스크립트는 nexa-sql 확장 구조 차용. 용어는 dir2대로 **`plugins/`** | 사용자 지시 "Plugin 크로스플랫폼 변환" · [port/43 §4](port/43-sql-i18n-extensions.md) EXT-401~456 · [port/20](port/20-dir2-preview-plugins.md) | | DR-8 | 10-03 | **외부 crate 기본 0 지향.** 허용 원장(§3): winit · softbuffer · wasmi · regex-lite(ops · dir2 계승) · 형제 경로 의존(nexa-ui 7 · nexa-license) · OS 바인딩(`windows`/`windows-core` · `objc2*` · `x11rb`). 추가는 §3에 건별 기록 후 | dir2 DR-8 · nexa-ui DR-3 · nexa-sql DR-3 | | DR-9 | 10-03 | **설정 폴더 = 포터블 우선 계승.** `NDIR_HOME` → exe 옆 `data/`(이미 존재 + 쓰기 가능 + `is_replaced_on_upgrade` 아님) → `nexa_conf::user_config_dir("nexa-dir")`. 배포 채널은 M7에서 확정(후보: Windows 포터블 zip + MSI(+ winget/choco 자산 승계 여부) · macOS pkg/dmg · Linux deb/rpm) | dir2 DR-3(포터블) · [port/41 §5-4 결정 1](port/41-sql-settings.md) · [port/44 §3-4](port/44-sql-ci-test-docs.md) | | DR-10 | 10-03 | **회귀 하네스 7층 + 자가 점검.** T0 정적(fmt·clippy·3-OS) → T1 단위 → T2 헤드리스 컨트롤(`RecordCtx`) → T3 헤드리스 앱 시나리오(`AppCore` + `FakePlatform` + 레이아웃 덤프 골든) → T4 프로세스 E2E(`NDIR_HOME` + `NDIR_STARTUP_CMD` + `*.dump`) → T5 `--selfcheck`(doctor · `--ci` 부분집합 · Help ▸ 자가 점검 창과 같은 함수) → T6 성능. **검증 매트릭스** [port/90](port/90-verification-matrix.md) = 이식 원장 ID ↔ 구현 ↔ 시험. 패닉 훅 → `/crash/<시각>.txt`(dir2 계승) | 사용자 지시 "회귀 테스트 하네스 · 핵심 기능 오류 즉시 확인" · [port/44 §5](port/44-sql-ci-test-docs.md) CI-101~120 | | DR-11 | 10-03 | **dir2 순수 로직 테스트 그대로 이식**(코어·vfs·tree·ops·term · 약 425개)이 패리티의 1차 증거. 이식으로 기대값이 달라지는 곳은 "dir2 기대값 = dir3 기대값" 고정물로 남긴다 | [port/22](port/22-dir2-ops-core.md) OPS · CI-117 | | DR-12 | 10-03 | **push 규칙.** 사용자가 "중간중간 commit과 push" 명시 → 슬라이스/마일스톤 완료 + 게이트 green이면 main push(자동). 형제 의존 변경은 nexa-ui → nexa-license → dir3 순. 버전 태그 push는 별도 승인. 복원 지점 태그 `baseline/pre-nexa-dir3-2026-10-03`을 nexa-ui(`c5a9667`)·nexa-license(`f1e282a`)에 생성·push 완료(10-03) | 사용자 지시 · [16 §4](16-doc-git-conventions.md) | | DR-13 | 10-03 | **다중 에이전트(ultracode)는 조사 단계에만 사용**(10-03 인벤토리 19건). 이후 구현은 단일 세션 순차 진행 — 사용자 "사용량이 너무 많다"(10-03) | 사용자 지시 | | DR-14 | 10-03 | **i18n = dir2 `.lang` 자원 유지**(en·ko·ja · `@fallback` · 사용자 오버레이 `/lang/*.lang`) + nexa-sql 방식의 **컴파일 타임 키 검사**(빌드 스크립트가 세 파일의 키 파리티·자리표시자 검사 → 불일치 = 빌드 실패). 설정 라벨은 i18n **키 문자열**(`Entry.label: &'static str`) — `Msg` enum 생성 단계는 두지 않는다 | [port/41 §5-4 결정 3](port/41-sql-settings.md) · [port/43 §2](port/43-sql-i18n-extensions.md) · [port/31 §2](port/31-catalog-settings-i18n.md) | | DR-15 | 10-03 | **로그 창 · 메모리 모니터 = nexa-sql 구조 차용**(dir2에 없는 신규 기능). ① 로그 = **메모리 링 버퍼**(상한 `log.max_lines` · 파일 I/O 없음 · 생산자는 막히지 않음) · 새 크레이트 **`ndir-log`**(`nsql-log` 복제 · LogKind/LogLayer를 탐색기 도메인으로 교체 · 외부 의존 0 → §3 원장 변화 없음) · 창 = `log_win.rs`(nexa-sql 복제). ② **상세 로그는 개발자 모드 전용**(`log.dev_mode` + 레이어 마스크 · 꺼져 있으면 비용 = 원자 읽기 1 + 분기 1 · 메시지는 `#[cold]` 경로에서만 조립). ③ **화면에는 소요 시간(ms)·조회 시간을 내지 않는다** — 로그에만(상태줄 `status.firstRender` 류 제거). **동작 결과**(선택 수 · 복사/이동 수 등)는 상태줄 허용. ④ 메모리 모니터 = `memstat`/`mem_win`/`memtrim` 복제 + dir3 카테고리(목록 트리 · 아이콘 캐시 · 미리보기/플러그인 · 터미널 스크롤백 · 로그 · 표면 · 실행 취소 기록 · 셸 메뉴 캐시) · 창이 닫혀 있으면 비용 0 · 구성요소별 추정 바이트와 OS 풋프린트의 차이는 "기타"로 드러낸다. ⑤ **상태줄 우측 = [탭 n/m][메모리][라이선스]**(맨 우측 = 라이선스 · 클릭 = 라이선스 창 · 메모리 클릭 = 메모리 창) — **DR-4의 "상태줄 배지 보류"를 정정**. 클릭 가능한 우측 세그먼트는 nexa-ctl `StatusBar`에 추가(DR-2 · 추가만 · nexa-sql은 자체 그리기라 영향 없음) | 사용자 지시(10-03) "nexa-sql처럼 로그 창 · 메모리 맵 · 개발용 상세는 개발자 모드에서만 · ms는 로그에만" · "상태바 맨 우측 = 라이선스 · 그 왼쪽 = 메모리" · nexa-sql `docs/48`(상세 로그) · `docs/80`(메모리) · 소스 `nsql-log` · `log_win.rs` · `memstat.rs` · `app/memory.rs` · `app/paint.rs:115-335`(상태줄 세그먼트) | | DR-16 | 10-03 | **탭 상태바**(dir2에 없는 신규 · [22](22-dir3-features.md) NEW-004·005). ① 배치 = 패널 안 탭 줄 → 네비+경로 바 → 목록 → **탭 상태바(패널 안 마지막 띠 · 높이 = bar_h)** — 도크는 패널 밖의 전폭 띠(두 패널 아래 · `main.rs::layout_core` 680-696)라 탭 상태바는 패널마다 하나씩 도크 바로 위에 놓인다(`Panel::set_bounds` panel.rs:408-434의 목록 높이에서 뺀다) · 설정 `layout.tab_statusbar`(기본 on). ② 컨트롤 = nexa-ctl `StatusBar` **클릭 가능한 세그먼트**(DR-15 ⑤와 같은 부품 · 추가만) — 세그먼트 = {id · 글리프/아이콘 · 문구 · 색조 · 툴팁} · 통지 = `(seg_id, Primary\|Secondary, anchor Rect)` — **좌클릭 = 상세 · 우클릭 = 메뉴**를 컨트롤 수준에서 분리. ③ 정보 공급자 포트 = 앱 trait `DirInfoProvider`(`probe(dir)` 워커 · 세대 번호 가드 · 탭별 캐시 · `details` · `menu` · `invoke`) — 첫 공급자 Git, 이후 디스크 여유 · 클라우드 동기 상태 등을 같은 틀로. ④ Git = 외부 crate 0: 브랜치/detached는 `.git/HEAD` 직접 읽기(worktree 포인터 · 상위 탐색), 상세는 `git status --porcelain=v2 --branch` 등 git CLI를 워커에서(없으면 브랜치만) · 프로세스 실행(창 없음)은 `platform/` · 갱신 = 탭 이동/활성 · `.git/HEAD`·`index` 감시 · 수동 · 디바운스. ⑤ 1차 = 읽기 전용 + 새로 고침 · 브랜치 이름 복사 · 여기서 터미널 열기 / 변경 명령(fetch·pull·push) = 2차. ⑥ 소요 시간은 로그에만(DR-15 ③) | 사용자 지시(10-03) "탭 영역 아래 · 도크 위에 탭 상태바 · 현재 디렉터리 정보(git 브랜치 · commit 수 · 온라인 상태) · 좌클릭 상세 · 우클릭 추가 메뉴" · dir2에 없음 | | DR-17 | 10-03 | **대량 전송 엔진 내장을 dir3 목표로 채택**(FastCopy · robocopy류 · 마일스톤 M9 · [22](22-dir3-features.md) NEW-006·007). dir2 전송 엔진(`ndir-ops` · DR-11 패리티 시험 유지) **위에 전략 계층**을 얹는다(큰 버퍼·비버퍼드 I/O · 큰/작은 파일 분리 · 작은 파일 병렬 · 해시 검증 · 미러/차등 · 재시도/재개 · 필터 · 속성 보존 · 속도 제한 · 작업 큐 · dry-run 보고서). OS 의존(비버퍼드 I/O · ACL/ADS/링크 · 볼륨 판정)은 `platform/` 포트(DR-5). 외부 crate 0 유지(DR-8). 진행 UI는 카드형 진행 창 + 상태바 진행 칸 + 완료 토스트 → 실행 취소로 개편. 로그는 메모리 로그(DR-15) + 선택적 보고서 내보내기. 설계 문서(T-97)를 먼저 쓴 뒤 구현. **제공 형태**: 엔진 = 플랫폼 중립 rlib 크레이트 **`ndir-xfer`**(OS 의존은 같은 크레이트 `os/` 포트 — nexa-dir `platform/`과 독립이라 단독 빌드 가능) · 전면 3 = ① **정적 링크 내장**(기본 · 포터블 단일 exe 유지) ② **별도 실행 파일 `nexa-copy`**(같은 rlib · robocopy식 인자 · 종료 코드 규약 · `--json` 진행 JSONL · T-82 패키징 포함) ③ **선택적 `cdylib` + 버전 있는 C ABI**(제3자 임베드 · 후순위). nexa-dir는 권한 상승/격리가 필요하면 ②를 자식 프로세스로 구동(`JobSpec` JSON stdin → `Progress`·`Report` JSONL stdout) → 입력·진행·결과는 처음부터 **직렬화 가능한 단일 모델**(외부 crate 0) | 사용자 지시(10-03) "복사/이동 진행 UI 미려하게" · "다수 파일 처리에 특화된 FastCopy · robocopy류 기능 내장" · "별도 실행 파일로도 · 내장 기능으로도 · 동적 라이브러리/정적 빌드 방법을 미리 설계" · dir2에 없음 | | DR-18 | 10-03 | **성능 향상 모드 = nexa-sql `perf.boost` 차용**([22](22-dir3-features.md) NEW-008). 단일 on/off 설정 `perf.boost`(기본 off) · `BOOST` 표(키 → 강제 값)를 **읽을 때 덮어쓰기**(`effective()` = 부스트 값 → 사용자 저장값 → 기본값 · 저장값은 절대 쓰지 않음 → 끄면 그대로 원복) · 설정 창은 강제되는 키를 잠금 표시(값 + "⚡ … 적용 중" 안내) · 바꾸면 해당 키를 다시 적용하고 상태줄 일시 안내. 대상 묶음 = 아이콘(행 셸 · 메뉴 · 툴바) · 갱신 주기(감시 폴링 · 아이콘 폴링 · 상태줄 메모리) · 렌더링(애니메이션 · 고속 스크롤 HUD · 미리보기 자동 로드) · 메모리(캐시 상한 · 힙 정리 · 스크롤백) · 감시. 덮을 대상이 되도록 해당 동작을 **먼저 설정 키로**(REGISTRY · 자주 안 바꾸면 HIDDEN) 꺼낸다. nexa-sql의 별도 `perf.mode`(full/balanced/low 단계)는 1차 범위 밖 | 사용자 지시(10-03) "nexa-sql처럼 성능 향상 모드" · nexa-sql `crates/nsql-settings/src/perf.rs`(`BOOST` :236-288 · `effective` :461 · 시험 `boost_forces_values_and_locks_without_touching_stored` lib.rs:7250) · `prefs_win.rs:632-637`(잠금 표시) | | DR-19 | 10-03 | **값 분류 원칙.** 소스의 고정값·하드코딩 수치를 셋으로 나눠 **모두 추출**한다. ① **상수** = 바뀌지 않는 고정값(포맷 · OS · 프로토콜 한계 · 정합성 불변식 · 시험 하네스) — 남길 때 이유를 코드 주석 한 줄로 ② **고급 설정** = 바꾸면 위치·속도가 달라지지만 자주 안 바꾸거나 다른 곳에 영향(폴링 간격 · 캐시 상한 · 임계 · 타임아웃 · 내부 레이아웃 지표) → REGISTRY `ADVANCED`(거의 안 바꾸면 `HIDDEN`) ③ **일반 설정** = 자주 바꾸거나 취향(보이는 크기 · 체감 시간 · 켜고 끄기). 설정 키 범위와 코드 클램프는 같아야 한다(불일치 = 키 범위로 정렬). 원장 = [23](23-settings-extraction.md)(값 · 위치 · 뜻 · 분류 · 제안 키 · 상태) — 성능 향상 모드(DR-18)의 덮을 대상 목록이기도 하다 | 사용자 지시(10-03) "변경되지 않을 고정값은 상수 · 바꾸면 위치/속도가 달라지지만 자주 안 바꾸거나 다른 곳에 영향 주는 값은 고급 설정 · 자주 바꾸거나 취향인 값은 설정으로 모두 추출" | | DR-20 | 10-03 | **1초 규칙 — 오래 걸리는 동작은 진행 중임을 보인다.** 1초 이상 결과가 나오지 않을 수 있는 동작(셸 기동 · 폴더 열기 · 셸 메뉴 불러오기 · 미리보기/플러그인 · 대량 목록 · 네트워크/클라우드 경로 등)은 **즉시 진행 상태를 표시**해 사용자가 목표 없이 기다리지 않게 한다(자리 표시 문구 · 회전 표시 · "불러오는 중" 항목 · 상태줄 칸 · 취소 수단이 있으면 함께). UI 스레드에서 막히는 호출은 워커로 옮기고(DR 아키텍처 §스레딩) 결과는 통지로 채운다. 소요 시간(ms) 자체는 화면이 아니라 로그에(DR-15 ③). 선례 = §71 우클릭 메뉴(즉시 열고 "불러오는 중" 뒤 채움) | 사용자 지시(10-03) "1초 이상 응답이 나오지 않는 동작은 진행 중 상태를 표시해 사용자가 목표 없이 기다리지 않게" · 계기 = 터미널 도크 클릭 후 무반응 대기 보고 | | DR-21 | 10-03 | **터미널 도크 = Windows Terminal과 같게 보이기**([22](22-dir3-features.md) NEW-012). Windows에서는 사용자의 Windows Terminal 설정(`%LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json` · 기본 프로필 + `profiles.defaults`)을 읽어 적용한다 — 글꼴 목록(쉼표 · 이 PC = "D2Coding, JetBrainsMono Nerd Font") · 글꼴 크기 · 색 구성표(미지정 = Campbell) · 커서 모양 · 여백 · 시작 명령. 새 설정 `term.follow_windows_terminal`(기본 on · 끄면 dir3 자체 `term.*` 설정). ndir-term에 SGR 3 **이탤릭** 추가(지금은 굵게 · 흐림 · 반전만). 불투명도 · 아크릴은 도크 영역만으로 표현할 수 없어 제외. 파일 읽기 = 외부 crate 0(JSON은 ndir-settings json 재사용) · 경로·존재 판정은 `platform/`(다른 OS = `None` → 자체 설정). macOS/Linux 터미널 앱 설정 따르기는 후속 | 사용자 지시(10-03 · 스크린샷) "Windows Terminal과 같게" · dir2에 없음 | | DR-22 | 10-03 | **창 투명도**([22](22-dir3-features.md) NEW-013). 설정 `window.transparency` 0~90 %(기본 0 · 일반 · 즉시 반영) · 창 전체에 OS 합성으로 적용(Windows = 레이어드 창 알파 · macOS = 창 알파 · X11 = `_NET_WM_WINDOW_OPACITY` · Wayland = 미지원 → 안내) · `platform/` 포트(DR-5) · 보조 창 포함. **성능 향상 모드(DR-18)가 켜지면 0으로 강제** — DR-18 `BOOST` 대상에 `window.transparency = 0` 추가(사용자 확인) | 사용자 지시(10-03) "창 투명도 설정" · "성능 향상 모드면 끈다" · dir2에 없음 | | DR-23 | 10-03 | (**DR-25로 정정** — 부하 = 시스템 값 · 네트워크 · 칸 안 항목) **상태줄 구성 = 칸 선택 + 순서 편집**(DR-15 ⑤ 확장 · [22](22-dir3-features.md) NEW-003). 우측 칸 기본 = [탭 n/m][CPU][메모리][디스크 I/O][라이선스](맨 우측 = 라이선스). CPU · 메모리 · 디스크 I/O는 **이 프로그램(프로세스)의 부하**(CPU % · 메모리 · 읽기/쓰기 바이트/초)이고 **기본 = 표시**. "상태줄 구성" = `toolbar.layout`과 같은 순서 편집기로 칸별 켜기/끄기 + 위치(새 키 `statusbar.layout`). 갱신 주기 = 고급 설정(그릴 때만 조회 · 앱을 깨우지 않음 — nexa-sql `mem.status_refresh_ms` 방식). OS 수집 = `platform/` 포트(Windows `GetProcessTimes` · `GetProcessMemoryInfo`(PrivateBytes) · `GetProcessIoCounters` / Linux `/proc/self/{stat,statm,io}` / macOS `proc_pid_rusage`). 클릭: 메모리 칸 → 메모리 창 · 라이선스 칸 → 라이선스 창 | 사용자 지시(10-03) "상태바에 이 프로그램의 CPU · 메모리 · 디스크 I/O · 기본 켬 · 상태바 구성에서 켜기/끄기와 위치 조정" | | DR-24 | 10-03 | **형제 저장소 소비자 기록 원칙.** nexa-ui · nexa-license를 고치면 그 저장소 `docs/CONSUMER-CHANGES.md`(최신 위 표)에 커밋마다 한 줄 — 차수/커밋 · 크레이트 · 변경 요약 · **종류**(추가 / 동작 변경 / 수정 / 문서) · 소비자별 영향(nexa-sql · nexa-dir3 · 발급 도구) · **검증 방법**(명령 + 화면에서 볼 곳) · **검증 상태**(`영향 없음(근거)` / `check` / `시험` / `실기` / `미검증` — 못 한 것은 미검증으로 남기고 빈칸 금지). 동작 변경·수정은 소비자 시험(nexa-sql `cargo test --workspace` · 별도 target-dir)까지. 소비자 세션은 pull 뒤 그 파일의 `동작 변경`·`미검증` 행부터 확인하고 결과를 상태 칸에 적는다. 절차 = [15 §2-4-1](15-dev-methodology.md). 첫 기재 = nexa-ui 8399601(111~119차 소급 · 119 글꼴 매칭 = 동작 변경 · nexa-sql 시험 729 통과) · nexa-license 54c8d71 | 사용자 지시(10-03) "ui · license의 수정이 이루어지면 함께 사용하는 프로그램이 변경을 인식하고 검증할 수 있도록 기록이 잘 남겨져야 한다" | | DR-25 | 10-04 | **DR-23 정정 — 상태줄 부하 = 시스템 전체 값 + 네트워크 · 칸 안 항목.** CPU · 디스크 · 네트워크는 **시스템(PC 전체) 값**(DR-23의 "이 프로그램(프로세스)의 부하"를 대체). 메모리 칸만 두 항목 = ① 이 프로그램(Dir) 메모리 ② 시스템 메모리 사용량(nexa-sql 상태바처럼). 디스크 칸 = 쓰기 · 읽기(바이트/초) · **네트워크 칸 신설** = 다운로드 · 업로드(바이트/초). 칸 기본 = [탭][CPU][메모리][디스크][네트워크][라이선스]. 칸과 칸 안 항목의 순서 · 표시 = 순서 편집 창(`statusbar.layout` · 툴바처럼 그룹/자식 · 상태줄 우클릭 · 설정 [편집…]) — 칸의 항목을 모두 끄면 칸이 빠진다. OS 수집 = `platform/sysload.rs`(Linux `/proc/{stat,meminfo,diskstats,net/dev}` + `VmRSS` · Windows `GetSystemTimes` · `GlobalMemoryStatusEx` · `IOCTL_DISK_PERFORMANCE` · `GetIfTable` · `K32GetProcessMemoryInfo` · macOS `host_statistics(64)` · `getifaddrs` · `proc_pid_rusage` · macOS 디스크 = 후속(IOKit)). 갱신 주기 · 그릴 때만 조회 · 클릭(메모리 → 메모리 창 · 라이선스 → 라이선스 창)은 DR-23 그대로. 설정 위치 = 일반 › 상태바(창 아래 상태줄) · 탭 › 상태바(탭 상태바) | 사용자 지시(10-04) "CPU · 메모리 · 디스크 각각의 정보는 시스템 상태값" · "네트워크 항목 추가 — Download/Upload" · "툴바 조정 화면처럼 상태바도 위치 조정" · "디스크 = Write/Read · 네트워크 = Download/Upload · 메모리는 nexa-sql 상태바처럼 ① Dir 프로그램의 메모리 ② 시스템 메모리 사용량" · 구현 0ad7599 · 9a8ed19 · journal 10-04 §9 · §10 | | DR-26 | 10-04 | **게이트 단계화 — 평소 quick · 조건부 full · 중요 시점 full.** push 전 게이트 = `scripts/gate.sh`(auto 기본). quick = fmt + 호스트 clippy + 마지막 전수 뒤 바뀐 크레이트 시험 + `--smoke`. full = 3-OS clippy + 전체 시험 + `--smoke` + `--selfcheck --ci` + T4 시나리오 · 통과 기록 = `target/gate/last-full`(PC별). auto가 full을 고르는 때 = 전수 기록 없음 · 마지막 전수 24시간(`NDIR_GATE_FULL_HOURS`) 경과 · 형제 저장소 HEAD 변경 · 핵심 경로(코어 rlib · OS 분기 · 설정 엔진 · 라이선스 · 빌드/CI/게이트 · 시나리오) 변경. 배포 · 태그 · 마일스톤 마감 · 병합 전 = full 한 번 더. quick으로 push했으면 CI(3-OS 전수)가 전수 역할(결과 확인 필수). `check-all.sh` = 형제 저장소까지 도는 최대 전수(수동). 종전 "모든 push 전 4단계 전수"(CLAUDE.md §5 · docs/18 §3)를 대체 | 사용자 지시(10-04) "모든 기능 수정에 전수 테스트를 수행할 필요는 없다 — 최근 수행 기록이 없거나 핵심 로직이 수정되어 영향도가 높은 경우가 아니라면, 일정 기간 테스트가 되지 않은 경우에만 전수를 하고, 배포 전과 같이 중요 시점에 한 번 더 확인하도록 절차 개선" · 구현 bba4739(scripts/gate.sh · CLAUDE.md §5) · journal 10-04 §16 | | DR-27 | 10-09 | **클릭 동작 = 뗄 때(Release).** 사용자 10-09 "특별히 업계 표준이거나 빠른 입력이 목적이 아니라면 마우스의 클릭 이벤트가 MouseDown에서 직접 동작하지 않고 Release 된 이후 동작하도록 · 풀다운 메뉴도 포함". 규칙 = 누른 대상을 기억 → **같은 대상 위에서 떼면 동작 · 밖에서 떼면 취소**(버튼 규칙) · 누름은 눌림 표시(강조)만. 적용 = 버튼 · 툴바 · 탭(전환/닫기) · 우클릭 메뉴 · 상태줄 · 메뉴바 항목 확정 · 체크박스 · 스위치 · 라디오 · 콤보/아이콘/위치/색 선택 · 팔레트 행 · 캐러셀 항목 · 경로 바 세그먼트. **예외(업계 표준 · 빠른 입력 — 누를 때 그대로)** = 목록/트리 행 선택 · 메뉴 열기 · 하위 메뉴 펼침 · 메뉴 라벨에서 누른 채 끌어 항목에서 떼기(표준 · 떼는 자리 항목 확정) · 스크롤바/스플리터/색 패널(SV · 색상 · 알파) 드래그 · 탭바/캐러셀 ◀▶ 단계 · 더블클릭 합성 · 도움말 배지. 새 컨트롤도 이 규칙을 따른다(nexa-ui 공통 · nexa-sql 같은 결정). 구현 = nexa-ui 180차 5a04e13(nexa-sql 세션) · 181차 71cde23 · dir3 9921d80 | 사용자 10-09 · journal 10-09 §1 | | DR-28 | 10-10 | **"정렬 없음" = 이름 오름차순(dir2와 의도된 차이 · PANEL-065).** 정렬 열이 하나도 없을 때 목록 순서는 dir2의 "OS 열거 순서" 대신 **이름 오름차순**으로 둔다(사용자 10-10 수용). 근거 = dir2는 Windows 전용이라 NTFS 열거가 사실상 이름순이었지만 Linux/macOS `readdir` 순서는 파일 시스템마다 임의(해시 · 생성 순) — 3-OS가 같은 결과를 내려면 이름순이 기준. 구현 = 888e126(T-128 · NEW-045) | 사용자 10-10 · journal 10-10 §5 | | DR-29 | 10-10 | **파일 드래그 기본 동작 = 받는 쪽 규칙(OS별) · 수식키만 지정.** Linux(XDND) 발신은 수식키가 없으면 동작을 **지정하지 않는다**(`XdndActionList` [복사, 이동]만 · 받는 쪽이 고름 · 지정 없음을 거부하는 대상에만 복사로 재시도) · Ctrl = 복사 · Shift = 이동만 지정. Windows = OLE `DoDragDrop`에서 탐색기(받는 쪽)가 결정(종전). 이름 상자 · 커서 = 받는 쪽이 돌려준 동작. 근거 = mutter는 XdndPosition 동작을 사용자 지정으로 채택해 받는 쪽 규칙을 덮음 · nautilus `nautilus_dnd_get_preferred_action`은 같은 FS + 노틸러스 캐시 원본일 때만 이동 · 외부 드롭은 복사(GNOME 50 소스). 사용자 10-10 "이동/복사 판단은 시스템 기본 규칙대로 · OS별 기본이 다를 수 있음 감안" → "현상태 유지". 구현 = ffc7258 · 76835cd(T-147) | 사용자 10-10 · journal 10-10 §10 · §12 | | DR-30 | 10-10 | **게시물 · 프로그램 내부 정보 = 영어 원본.** 패키지 메타데이터(deb/rpm/MSI/pkg · winget/choco/homebrew · `.desktop` · Cargo.toml description) · 릴리스 노트/CHANGELOG · 동봉 문서(README · LICENSE · NOTICE · 설치/제거 안내) · about 문구 · 게시 채널 본문은 **영어**로 쓴다 · 한글/일본어는 `Comment[ko]`처럼 덧붙이는 현지화 항목만 · UI 문자열은 i18n 키(en 원본 · DR-14) · **저장소 개발 문서(docs/ · journal · 커밋 메시지)는 한글 그대로**. 동봉 README = 영어 · 한글본 = `README.ko.md`. 사용자 10-10 "패키지 게시 작업은 기본 문서 · 설명 · 버전 등 프로그램 내부 정보를 영어로". 구현 = f349dfa(CLAUDE.md §5 · docs/16 §5-6 · packaging/README) | 사용자 10-10 · journal 10-10 §13 | ## 2. ADR 색인 | ADR | 주제 | 상태 | | --- | --- | --- | | (예약) 20-adr-0001-platform-ports | OS 분기 포트 설계(셸 메뉴·휴지통·DnD·PTY) — M4 착수 시 작성 | 📐 | | (예약) 21-adr-0002-distribution | 3-OS 배포 채널 — M7 착수 시 작성 | 📐 | ## 3. 외부 crate 원장 | crate | 용도 | 라이선스 | 등재 | 비고 | | --- | --- | --- | --- | --- | | `winit 0.30` | 창·입력 | Apache-2.0 | DR-1 | nexa-sql·clip·beep과 같은 판 | | `softbuffer 0.4` | CPU 픽셀 제출 | MIT/Apache-2.0 | DR-1 | Wayland dlopen | | `wasmi 1.1` | 플러그인 런타임 | MIT/Apache-2.0 | DR-7 | dir2·nexa-sql 동일 판 | | `windows 0.62`(cfg(windows)) | 셸 컨텍스트 메뉴(IContextMenu · HMENU 열거 · InvokeCommand) — 기능 Foundation·Graphics_Gdi·System_Com·UI_Shell(+Common)·UI_WindowsAndMessaging | MIT/Apache-2.0 | DR-8 OS 바인딩 | dir2와 같은 판 · 10-03 T-51 B-1부터 | | `wat 1`(dev) | 시험 전용 — WAT 텍스트 → .wasm 조립(격리·브레이커·ABI v2 시험) | Apache-2.0 WITH LLVM-exception | DR-7 | dir2 dev-dependency 동일 · 배포 바이너리에 안 들어간다 | | `regex-lite 0.1` | 일괄 이름 변경 정규식 | MIT/Apache-2.0 | DR-8 | dir2 `nexa-ops` 계승 | | `windows`/`windows-core 0.62` | Win32 바인딩(platform/windows만) | MIT/Apache-2.0 | DR-8 | 기능 플래그는 필요한 것만 · 10-05 d24bc51(T-147 OLE 드래그 발신): 기능 `Win32_System_Ole` · `Win32_System_Com_StructuredStorage` · `Win32_System_SystemServices` 추가 · `windows-core 0.62` 직접 의존(`#[implement]`가 `::windows_core` 경로를 가리킴 · 이미 끌려오던 같은 판 · Cargo.lock 1줄) | | `objc2` · `objc2-app-kit` · `objc2-foundation` | macOS(platform/macos · Dock 아이콘) | MIT | DR-8 | winit과 같은 판 | | `x11rb 0.13` | Linux 모달 transient 속성 | MIT/Apache-2.0 | DR-8 | nexa-sql 선례 | | (dev) `wat` | WASM 격리 시험 조립 | MIT/Apache-2.0 | DR-11 | dir2 dev-dep 계승 | | 형제 경로 | `nexa-gfx` `nexa-ctl` `nexa-conf` `nexa-font` `nexa-fs` `nexa-dlg` `nexa-sys` · `nexa-license` | PolyForm NC | DR-1·4 | `../nexa-ui` · `../nexa-license` | ## 4. 열린 결정(사용자 결정 대기 — 기본값으로 진행 중) | # | 쟁점 | 지금 적용 중인 기본값 | 근거 | | --- | --- | --- | --- | | Q-1 | 라이선스 `Feature`·`Tier`·`Kind` 구성 | Feature 0개(게이트 없음) · Tier/Kind는 nexa-license 공통 그대로 | dir2에 유료 기능 정의 없음(LIC-155) | | Q-2 | Windows 배포 채널(포터블 exe/zip·Inno·choco·winget 승계 vs MSI) | 포터블 zip + MSI 둘 다 생성 · winget/choco 제출은 사용자 결정 | [port/44 §3-4](port/44-sql-ci-test-docs.md) | | Q-3 | 예산 게이트 수치(dir2 exe ≤10 MB · RSS ≤30 MB) | 측정만 하고 게이트는 M7에서 | winit·softbuffer·wasmi 증가분 실측 뒤 | | Q-4 | macOS/Linux 셸 컨텍스트 메뉴 범위 | 자체 메뉴(열기·연결 프로그램·파일 관리자에서 보기·속성) + "OS 메뉴 열기" 없음 | [port/19](port/19-dir2-shell-integration.md) | | Q-5 | `kind=org` 라이선스 단독 설치 허용 | nexa-sql과 같이 허용(경고 없음) | LIC-172 | | Q-6 | 클라우드(OAuth) 기능의 3-OS HTTP 스택 | M6에서 결정(OS 네이티브 API별 vs 최소 crate) — **사용자 10-05: 클라우드 묶음(CLOUD-001~099 · WINB-036~042 · O-001~020 · GAP-019)은 TODO에 올리고 대기**(T-72 · T-129 · 착수할 때 이 결정을 연다) | [port/21](port/21-dir2-cloud.md) | | Q-7 | 성능 거버너(nexa-sql `perf.mode`/`perf.boost` · `nexa-sys` 신호) 도입 여부 | 도입하지 않음(dir2에 대응 기능 없음 · `ndir-settings`에 `perf.rs` 없음) — 부하원이 늘면 재검토 | [port/41](port/41-sql-settings.md) SET-051~053 | | Q-8 | macOS 화면 제출 경로(nexa-sql `gfx.mac_present` = softbuffer/iosurface) 설정 노출 여부 | 노출하지 않음(`present::set_mode` 미호출 = softbuffer 기본 · dir2에 대응 키 없음) — 맥 실기 계측 뒤 재검토 | [port/40](port/40-sql-app-skeleton.md) §1-10 |