VimAction 프로젝트의 기술 결정 히스토리 SSOT — 아키텍처, 툴링, 라이브러리, 빌드/배포, 테스트 전략 등 모든 기술 결정의 기록과 조회. Use this skill whenever a technical decision is made, changed, or reversed ("~하기로 했어", "~로 결정했어", "이 결정 기록해줘", "X 대신 Y로 바꾸자"), and whenever someone asks about a past decision's history or rationale ("왜 X로 결정했었지?", "예전에 어떻게 하기로 했더라?", "이거 언제 바뀐 거야?"). Also use BEFORE overturning or revisiting any existing decision, even if the user doesn't say "decision" explicitly.
Scanned 8/30/2026
Install to Claude Code
npx -y skills add pilyang/vim-action --skill decisions --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Decisions?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/pilyang-decisions)More formats (shields.io, HTML) on the badges page.
---
name: decisions
description: VimAction 프로젝트의 기술 결정 히스토리 SSOT — 아키텍처, 툴링, 라이브러리, 빌드/배포, 테스트 전략 등 모든 기술 결정의 기록과 조회. Use this skill whenever a technical decision is made, changed, or reversed ("~하기로 했어", "~로 결정했어", "이 결정 기록해줘", "X 대신 Y로 바꾸자"), and whenever someone asks about a past decision's history or rationale ("왜 X로 결정했었지?", "예전에 어떻게 하기로 했더라?", "이거 언제 바뀐 거야?"). Also use BEFORE overturning or revisiting any existing decision, even if the user doesn't say "decision" explicitly.
---
# VimAction 기술 결정 기록 (Decision Log)
이 스킬은 VimAction의 **기술 결정 히스토리의 단일 소스(SSOT)** 입니다. 결정 문서는 전부 `references/`에 있고, 이 파일은 규칙과 인덱스만 관리합니다.
역할 분담: 이 스킬은 "**언제, 왜** 그렇게 결정했는가"(히스토리)를 담당하고, 결정이 반영된 "**지금** 구조가 어떤가"(최종 상태)는 `architecture` 스킬이 담당합니다. 결정 기록의 진입점은 항상 이 스킬입니다.
## 워크플로우 1 — 결정 기록
새 기술 결정이 생기거나 기존 결정이 바뀌면:
1. **항상 신규 문서를 추가**합니다: `references/` 아래 `yyyymmdd_<kebab-case-title>.md` (`_template.md` 복사). 날짜는 **결정일**이며 반드시 파일명에 포함 — 기록 시점의 날짜는 `date +%Y%m%d`로 확인합니다. 기존 결정 문서는 수정하거나 재작성하지 않습니다. 문서 하나가 결정 하나의 불변 스냅샷이어야, 나중에 "그때 왜 그랬는지"를 있는 그대로 신뢰할 수 있습니다.
- **문서 하나 = 결정 하나.** 큰 설계 안에 독립적으로 뒤집힐 수 있는 결정이 여러 개 섞여 있으면 문서를 나눕니다 (예: "전략 디스패치 구조"와 "AX 감지 타임아웃 값"은 별도 문서). 이렇게 해야 나중에 그 결정 하나만 supersede할 수 있고, 나머지 유효한 결정이 함께 폐기되지 않습니다.
2. **기존 결정을 뒤집는 경우** (supersede):
- 새 문서의 `Supersedes` 섹션에 옛 문서를 명시합니다.
- 옛 문서에는 **맨 위에 한 줄만** 추가합니다: `> Superseded by [yyyymmdd_새문서.md](yyyymmdd_새문서.md)` — 본문은 그대로 둡니다. 파일을 직접 연 사람도 낡은 결정임을 즉시 알 수 있게 하기 위한 유일한 허용 수정입니다. 부분 supersede는 `> Superseded (부분) by ... — <뒤집힌 부분> / <유효한 부분>` 형태로 범위를 명시합니다.
- 옛 문서가 **뒤집힌 결정만 담고 있다면** (다른 유효한 컨텍스트가 없다면) 아래 인덱스 테이블에서 **제거**합니다. 제거한 문서 중 히스토리 가치까지 소진된 것(단명한 과도기 규칙, 이행이 끝난 스케줄링 결정 등)은 **파일도 삭제**할 수 있습니다 — git 히스토리가 아카이브입니다. 실측 기록·위험 분석 등 재참조 가치가 남아 있거나 애매하면 파일은 남깁니다.
- 옛 문서에 아직 유효한 다른 결정·컨텍스트가 섞여 있어 제거 여부가 **애매하다면, 임의로 판단하지 말고 사용자에게 확인**합니다 (마킹·인덱스 제거를 보류하고 상황을 설명한 뒤 질문). 잘못 제거하면 유효한 결정이 컨텍스트에서 사라지고, 잘못 남기면 낡은 값이 계속 주입됩니다 — 문서 하나 = 결정 하나 원칙을 지켰다면 이 애매함 자체가 드뭅니다.
3. **인덱스 테이블을 반드시 갱신**합니다. 인덱스에 없는 문서는 다음 작업자의 컨텍스트에 주입되지 않습니다 — 이것이 폐기된 결정이 새 작업을 오염시키지 않게 하는 메커니즘입니다. 반대로, 인덱스를 빼먹으면 유효한 결정도 없는 것이 됩니다. 인덱스 요약은 **한 줄**로 짧게 — 상세 근거는 문서 몫이고, 인덱스는 "어떤 결정이 있는지 찾는" 용도입니다.
4. **구조·아키텍처에 영향이 있는 결정이면, 같은 플로우에서 `architecture` 스킬의 해당 reference(최종 상태)도 갱신**합니다. 결정 문서는 "왜 바뀌었는가"를, architecture reference는 "바뀐 결과가 무엇인가"를 담습니다. 여기서 갱신을 빼먹으면 두 스킬이 서로 다른 구조를 말하게 됩니다.
기록하지 않는 것: 사소하거나 코드만 봐도 자명한 선택. 결정 문서의 가치는 코드에서 역추적할 수 없는 맥락(근거, 기각된 대안)에 있습니다.
## 워크플로우 2 — 결정 조회
과거 결정의 경위·근거를 물으면 아래 인덱스에서 관련 항목을 찾아 **해당 문서만** 읽습니다. 전부 읽지 마세요. 인덱스에 없는(폐기된) 문서는 "그때 왜 그렇게 했다가 바뀌었는지" 같은 히스토리 조사가 목적일 때만 `references/` 디렉토리에서 직접 찾아 읽습니다 (삭제된 문서는 git 히스토리에서).
## Decision Index
도메인별 섹션, 각 섹션 안은 결정일 순. 요약은 결정의 핵심 한 줄 — 근거·대안·실측은 문서에 있습니다.
### 빌드·설정·배포
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-12 | YAML 설정 (Yams) | 설정은 전부 YAML + Yams 파싱 (루트는 20260801, 3계층 병합·자동 리로드는 20260802 부분 supersede) | [20260712_yaml-three-layer-config.md](references/20260712_yaml-three-layer-config.md) |
| 07-12 | 엔진 테스트는 Swift Testing | 픽스처 파라미터라이즈드에 적합, UI 테스트는 XCTest 유지 | [20260712_swift-testing-for-engine-tests.md](references/20260712_swift-testing-for-engine-tests.md) |
| 07-12 | 단일 코어 SPM 패키지 | 순수 Swift 모듈은 VimActionCore 단일 패키지의 다중 타깃으로 | [20260712_single-core-spm-package.md](references/20260712_single-core-spm-package.md) |
| 07-12 | GitHub Actions CI | macos-26 병렬 2잡(엔진 테스트+앱 빌드), Xcode 고정, 사이닝 off | [20260712_github-actions-ci.md](references/20260712_github-actions-ci.md) |
| 07-12 | 샌드박스 해제 + Developer ID | CGEventTap/AX가 샌드박스 불가 → MAS 포기, 직접 배포 | [20260712_disable-sandbox-developer-id.md](references/20260712_disable-sandbox-developer-id.md) |
| 07-12 | Active tap + AX 단독 온보딩 | 메인 탭은 처음부터 .defaultTap, 권한은 Accessibility만 요청 | [20260712_active-tap-ax-only-onboarding.md](references/20260712_active-tap-ax-only-onboarding.md) |
| 08-01 | 릴리스 배포 금지 게이트 해제 | M3 완료 — 무로그 삼킴 0건+위험 심사 4건 종결, 로그·switch 계약 승계 | [20260801_release-block-gate-lifted.md](references/20260801_release-block-gate-lifted.md) |
| 08-01 | 설정 루트 `~/.config/vim-action/` | 개발자 친화(dotfiles) — Application Support 부분 supersede | [20260801_config-root-dot-config.md](references/20260801_config-root-dot-config.md) |
| 08-01 | 앱별 on/off는 config.yaml 단일 소유 | 프로파일 스키마에서 enabled 제거, profiles/는 특수 동작 전용 | [20260801_app-enable-config-yaml-only.md](references/20260801_app-enable-config-yaml-only.md) |
| 08-01 | config.yaml 스키마 v1 | apps는 bundle-id→bool 맵, 미지 키 warn+무시, 리로드 실패 시 직전 유지 (병합 규칙은 20260802 부분 supersede) | [20260801_config-yaml-schema-v1.md](references/20260801_config-yaml-schema-v1.md) |
| 08-01 | 프로파일 재정의는 모션 단위 | motions가 매핑 테이블 원소 교체 — 편집·Visual 자동 전파, 액션 단위 기각 | [20260801_profile-motion-override-unit.md](references/20260801_profile-motion-override-unit.md) |
| 08-01 | 프로파일 스키마 v1 필드 | name·scroll·motions 구성, 문자 키 v1 제외, M4 전부 구현 (disabled_actions·표기는 08-02 부분 supersede) | [20260801_profile-schema-v1-fields.md](references/20260801_profile-schema-v1-fields.md) |
| 08-01 | 설정 UI는 YAML 읽기 전용 | Yams 주석 미보존 — UI는 표시+파일 열기만 (표시 대상은 20260802, 쓰기 금지 범위는 20260809 부분 supersede) | [20260801_settings-ui-read-only-yaml.md](references/20260801_settings-ui-read-only-yaml.md) |
| 08-01 | UserDefaults↔YAML 소유권 경계 | defaults=런타임·안전 상태(마스터 토글·탈출 옵션), YAML=사용자 편집 설정 | [20260801_userdefaults-yaml-ownership.md](references/20260801_userdefaults-yaml-ownership.md) |
| 08-02 | 설정 계층은 VimActionConfig 타깃 | VimActionCore 새 타깃(VimEngine+Yams, Yams는 그 타깃에만) — headless 테스트·의존 격리 | [20260802_config-layer-vimactionconfig-target.md](references/20260802_config-layer-vimactionconfig-target.md) |
| 08-02 | disable은 매핑 값 `disabled` | disabled_actions 폐기 — motions/actions 매핑 값으로 통일, 빈 배열은 warn+무시 (actions 값 어휘는 20260802 자기 키 재정의로 부분 supersede) | [20260802_profile-disable-via-mapping-keyword.md](references/20260802_profile-disable-via-mapping-keyword.md) |
| 08-02 | 액션 자신의 키 재정의 | `actions:` 값에 시퀀스 허용 — 자기 키만 교체(모션 접두는 motions 유지), scroll은 disabled 전용 | [20260802_action-own-key-override.md](references/20260802_action-own-key-override.md) |
| 08-02 | 설정 키워드 소문자 통일 | modifier·키 이름 전부 소문자 snake_case, v1 키 11종, 대소문자 관용 없음 | [20260802_config-keyword-notation-lowercase.md](references/20260802_config-keyword-notation-lowercase.md) |
| 08-02 | 번들 기본 프로파일 동봉 | Slack·Notion 기본 프로파일 포함 — 설치 즉시 위험 해소 + 실물 예시(전달 방식은 20260802 시딩으로 부분 supersede) | [20260802_bundled-default-profiles-slack-notion.md](references/20260802_bundled-default-profiles-slack-notion.md) |
| 08-02 | scroll 재정의 값 1...200 | 스크롤은 카운트 33과 곱해지는 증폭 축 — 범위 밖은 warn+무시 | [20260802_scroll-override-bounds.md](references/20260802_scroll-override-bounds.md) |
| 08-02 | append 모션은 base를 따라감 | charRightForAppend/lineEndForAppend는 어휘 비노출 — char_right/line_end 재정의 자동 상속 | [20260802_append-motions-follow-base-override.md](references/20260802_append-motions-follow-base-override.md) |
| 08-02 | 번들 기본값은 시딩 | 병합 계층 폐기 — 없는 파일만 복사, 읽기는 사용자 파일 1계층(계층 출처 소멸), 기존 파일 미갱신 수용 | [20260802_bundled-defaults-seeded-not-merged.md](references/20260802_bundled-defaults-seeded-not-merged.md) |
| 08-02 | Package.resolved 커밋 | Yams가 첫 외부 의존 — CI·로컬 버전 고정(파싱 테스트가 Yams 해석에 의존) | [20260802_package-resolved-committed.md](references/20260802_package-resolved-committed.md) |
| 08-02 | 설정 리로드는 메뉴바 수동 트리거 | 파일 감시 폐기 — 'Reload Config' 클릭, 실패는 클릭 자리에서 가시화, 자동 감시는 재개 조건부 | [20260802_config-reload-manual-menubar-trigger.md](references/20260802_config-reload-manual-menubar-trigger.md) |
| 08-02 | 메뉴바 최전면 앱 편의 기능 2종 | bundle id 복사 + 프로파일 scaffold 생성·열기 — non-self 앱 캐시 전제, 기존 파일 무수정 | [20260802_menubar-frontmost-app-conveniences.md](references/20260802_menubar-frontmost-app-conveniences.md) |
| 08-02 | 비자신 캐시는 게이트 소유 + `@Observable` | 캐시·순수 파생을 `FrontmostAppGate`에, 판정은 계속 최전면 — 자기 활성화는 Preferences 경로에서 실측 (갱신 위치는 20260814 짝 확장으로 부분 supersede) | [20260802_frontmost-gate-non-self-cache-observable.md](references/20260802_frontmost-gate-non-self-cache-observable.md) |
| 08-02 | ConfigError 가시화·적용 의미론 | 메뉴 상태 라인 상시 + 리로드 실패만 NSAlert, 최초 로드는 부분 적용·이후 실패는 직전 유지 | [20260802_config-error-visibility-and-apply-semantics.md](references/20260802_config-error-visibility-and-apply-semantics.md) |
| 08-02 | App Icon은 Icon Composer `.icon` | legacy는 macOS 26이 회색 컨테이너에 강제 합성(실측) — appiconset 제거, 소스 벡터는 stroke가 아닌 외곽선 fill이어야 함 (26.5 전제는 20260812 배포 타깃 결정으로 부분 supersede) | [20260802_app-icon-icon-composer.md](references/20260802_app-icon-icon-composer.md) |
| 08-02 | 설정 창 열린 동안만 Dock 아이콘 | `.regular` 승격(앱 메뉴 동반 수용) — 열림=`onAppear`(창이 key가 안 됨, 실측)·닫힘=`willClose` (닫힘 판정 술어는 20260812 창 동일성으로 부분 supersede) | [20260802_dock-icon-while-settings-open.md](references/20260802_dock-icon-while-settings-open.md) |
| 08-09 | UI 쓰기는 라인 편집만 | 재직렬화 금지는 유지, 값 토큰 교체·한 줄 삽입은 허용 — 안전 계약 3종(에러 상태 거부/애매하면 nil+결과 자가검증/파일 열기 폴백) | [20260809_config-yaml-line-edit-writes.md](references/20260809_config-yaml-line-edit-writes.md) |
| 08-09 | 설정 창은 3탭 | General(권한·Behavior·접힌 Diagnostics)/Apps(기본 선택)/About, 460×560 고정 — 권한 섹션은 신뢰 상태에 따라 자리 이동 | [20260809_settings-window-three-tabs.md](references/20260809_settings-window-three-tabs.md) |
| 08-09 | 미허용 발견성은 push 2종 | 런치 1회 자동 오픈(`openSettings`를 `MenuBarExtra` label에서 — `sendAction`은 macOS 14부터 사망) + 메뉴 상시 경고 행 (26.5 전제는 20260812 배포 타깃 결정으로 부분 supersede — 결론 유지) | [20260809_permission-discoverability-push.md](references/20260809_permission-discoverability-push.md) |
| 08-10 | 자동 업데이트는 Sparkle 2.x | appcast + EdDSA·코드서명 이중 검증, 샌드박스 해제라 XPC 불필요 — 자체 구현 기각 | [20260810_sparkle-auto-update.md](references/20260810_sparkle-auto-update.md) |
| 08-10 | 배포 패키징은 DMG | 첫 설치 UX·설치 위치 안정성 — Sparkle·cask 공용, zip 기각 | [20260810_dmg-packaging.md](references/20260810_dmg-packaging.md) |
| 08-10 | Homebrew는 personal tap | 본진은 notability 미달 — `pilyang/homebrew-*` tap으로 시작, 도달 시 본진 이관 | [20260810_homebrew-personal-tap.md](references/20260810_homebrew-personal-tap.md) |
| 08-10 | 릴리스는 tag push GH Actions | tag → 빌드·서명·공증(notarytool, ASC API 키)·DMG·appcast·Release 업로드, 버전은 tag 주입 | [20260810_tag-push-release-pipeline.md](references/20260810_tag-push-release-pipeline.md) |
| 08-10 | appcast는 Releases 자산 | `releases/latest/download/appcast.xml` 고정 URL — Pages·raw 기각, 정식 릴리스만 non-prerelease | [20260810_appcast-hosting-github-releases.md](references/20260810_appcast-hosting-github-releases.md) |
| 08-11 | 업데이트 확인 UX — 표준 동의·3자리 | 자동 확인은 Sparkle 표준 프롬프트(기본 강제 없음), 버튼은 메뉴바+About·토글은 General | [20260811_sparkle-updater-ui-and-consent.md](references/20260811_sparkle-updater-ui-and-consent.md) |
| 08-11 | Sparkle 중첩 실행물 파이프라인 재서명 | SPM 아티팩트가 adhoc — XPC·Autoupdate·Updater.app을 Developer ID+runtime+timestamp로 재서명 후 앱 씰 재생성 (공증 Invalid 실측) | [20260811_sparkle-nested-resign-in-pipeline.md](references/20260811_sparkle-nested-resign-in-pipeline.md) |
| 08-11 | 릴리스 버전은 tag semver 하나 | CFBundleVersion(=Sparkle 비교축)까지 X.Y.Z 동일 주입, 별도 빌드 번호 없음 — 로컬 빌드(1)는 업데이트 미제안 엣지 수용 | [20260811_release-version-semver-cfbundleversion.md](references/20260811_release-version-semver-cfbundleversion.md) |
| 08-12 | Dock 아이콘 닫힘은 창 동일성 | 캡처한 설정 창이 닫힐 때만 강등 — Sparkle titled 창 오탐 해소, 못 잡으면 강등 안 함(fail-safe) (캡처 방식은 같은 날 창 전달로 부분 supersede) | [20260812_dock-icon-close-signal-window-identity.md](references/20260812_dock-icon-close-signal-window-identity.md) |
| 08-12 | Dock 아이콘 기준 창은 뷰가 전달 | 열거 캡처가 도그푸딩에서 빈손(닫아도 아이콘 잔류) — `SettingsWindowReader`(`viewDidMoveToWindow`)가 자기 창을 직접 전달, `windows` seam·찾기 술어 제거 | [20260812_dock-icon-settings-window-handoff.md](references/20260812_dock-icon-settings-window-handoff.md) |
| 08-12 | 서명 잡 외부 툴은 다이제스트/SHA 핀 | Sparkle tarball SHA-256 검증·create-dmg 커밋 SHA·actions 풀 SHA+Dependabot — SPM 핀과 동일 원칙, 키체인은 DMG 서명 직후 삭제 | [20260812_ci-signing-job-tools-digest-pinned.md](references/20260812_ci-signing-job-tools-digest-pinned.md) |
| 08-12 | Hardened Runtime은 pbxproj 고정 | 앱 타깃 두 config에 `ENABLE_HARDENED_RUNTIME = YES` — 워크플로 편집에 안 사라지고 로컬 빌드도 하드닝, Debug 디버깅은 base 엔타이틀먼트 주입으로 유지 | [20260812_hardened-runtime-pinned-in-pbxproj.md](references/20260812_hardened-runtime-pinned-in-pbxproj.md) |
| 08-12 | 로그인 시 자동 시작은 `SMAppService.mainApp` | opt-in 토글(기본 off, 묵시적 등록 없음) — 상태 SSOT는 `status` 하나(UserDefaults 미러 금지: 시스템 설정에서 직접 끌 수 있어 어긋난다), 창 열 때 재조회 | [20260812_launch-at-login-smappservice-status-ssot.md](references/20260812_launch-at-login-smappservice-status-ssot.md) |
| 08-12 | 배포 타깃은 macOS 14.0 | 26.5는 Xcode 생성 기본값 오입 — 코드 무변경 하한 14.0 확정(13.0은 `@Observable`·`openSettings`로 불가), CI 하한 게이트(오버라이드 빌드+pbxproj 단언), cask는 릴리스 후 `:sonoma`+arm64 가드 | [20260812_deployment-target-macos-14.md](references/20260812_deployment-target-macos-14.md) |
| 08-12 | README 데모 미디어 재생성 파이프라인 | `docs/assets/` 미디어는 `assets/readme/`(비추적) 소스+네이티브 Swift 스크립트로 재생성(ffmpeg 무의존) — lock 글리프는 SF Symbol 렌더, icon.png는 NSWorkspace 추출 | [20260812_readme-demo-media-native-render-pipeline.md](references/20260812_readme-demo-media-native-render-pipeline.md) |
| 08-13 | main 브랜치 보호 — CI 3잡 required | auto-merge가 CI를 안 기다린 실측(#54) — 3잡 전부 required, strict=false·enforce_admins=false(직접 docs push 유지) | [20260813_main-branch-protection-required-checks.md](references/20260813_main-branch-protection-required-checks.md) |
| 08-14 | 메뉴바 disabled 앱 인디케이터 | 앱별 off는 `minus.square`(미채움=통과 축), 표시 축은 비자신 캐시·게이트 판정은 최전면 유지, 우선순위는 토글 off와 Secure Input 사이 | [20260814_menubar-disabled-app-indicator.md](references/20260814_menubar-disabled-app-indicator.md) |
### 프로젝트 운영·커뮤니티
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 08-13 | 외부 기여는 이슈 우선 | 이슈 환영 + PR은 사전 논의 필수(오타·문서 예외), AI 관리 체제는 README·CONTRIBUTING에 명시, AI 생성 PR은 테스트·자기 설명 가능 시만 | [20260813_external-contribution-policy.md](references/20260813_external-contribution-policy.md) |
| 08-13 | 이슈 분류는 vim/app × bug/feature | 템플릿 4종이 `area:vim`/`area:app` 자동 부착, 계열별 필수 필드 강제(드롭다운 기각), blank issue 허용 유지 | [20260813_issue-taxonomy-vim-app-split.md](references/20260813_issue-taxonomy-vim-app-split.md) |
### 이벤트 탭 — 진입·번역·수명
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-12 | 단일 이벤트 탭 파이프라인 | 진입점은 단일 CGEventTap, 해석(엔진)과 실행(어댑터) 분리 | [20260712_single-event-tap-pipeline.md](references/20260712_single-event-tap-pipeline.md) |
| 07-12 | 합성 이벤트 마커와 안전장치 | userData 마커 + 단일 ActionExecutor로 무한 루프 방지 | [20260712_synthetic-event-marker-and-failsafe.md](references/20260712_synthetic-event-marker-and-failsafe.md) |
| 07-13 | 탭 자동복구 워치독 | 완전정지·장기스톨 대비 CGEventTapIsEnabled 주기 폴링 | [20260713_tap-reenable-watchdog-polling.md](references/20260713_tap-reenable-watchdog-polling.md) |
| 07-16 | CGEvent→Key 번역 방식 | UCKeyTranslate + ASCII 레이아웃, 번역 불가 nil=통과, @MainActor | [20260716_cgevent-key-translation-ascii-layout.md](references/20260716_cgevent-key-translation-ascii-layout.md) |
| 07-16 | KeyTranslator total function 가드 | keyDown 외 타입은 번역기 내부 가드로 nil | [20260716_keytranslator-total-function-keydown-guard.md](references/20260716_keytranslator-total-function-keydown-guard.md) |
| 07-17 | KeyTranslator 레이아웃 캐싱 | 레이아웃 Data 캐시 + 분산 노티 무효화, 실패 시 캐시 폐기 | [20260717_keytranslator-layout-caching.md](references/20260717_keytranslator-layout-caching.md) |
| 07-18 | 가로채기 마스터 토글 의미론 | off=tapEnable(false)+엔진 리셋, 설정은 컨트롤러 프로퍼티 SSOT | [20260718_interception-toggle-semantics.md](references/20260718_interception-toggle-semantics.md) |
| 07-19 | 워치독 스톨 게이트 | 워치독은 스톨 종료 후 복구 전담 — 스톨 중 재활성화 보류 | [20260719_watchdog-stall-gate-post-stall-recovery.md](references/20260719_watchdog-stall-gate-post-stall-recovery.md) |
| 07-19 | Secure Input 전용 상태 | OS 억제는 전용 상태로 표시, 우선순위 고장>토글off>SEI | [20260719_secure-input-status.md](references/20260719_secure-input-status.md) |
| 07-25 | 탭 메인 런루프 유지 확정 | 전용 스레드 전환 기각(3-에이전트 리뷰), 재검토 트리거 3종 명시 | [20260725_tap-main-runloop-retention.md](references/20260725_tap-main-runloop-retention.md) |
| 07-25 | 콜백 경량 불변식 | 탭 콜백 동기 구간은 번역+엔진 step+캐시 읽기로 제한 | [20260725_callback-light-invariant.md](references/20260725_callback-light-invariant.md) |
| 07-25 | 마커 가드는 콜백 최우선 판정 | 마커 확인은 handleKeyDown 최상단 — 상태 무관 불변식 | [20260725_marker-guard-highest-precedence.md](references/20260725_marker-guard-highest-precedence.md) |
| 07-26 | Secure Input은 배달만 억제 | 실측 — SEI는 활성화를 안 막음, .secureInput은 .failed 하위 구분으로 재정의 | [20260726_secure-input-suppresses-delivery-not-enablement.md](references/20260726_secure-input-suppresses-delivery-not-enablement.md) |
### 엔진 — 모드·문법·취소
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-12 | 순수 Swift 모드 엔진 | 모드 엔진은 macOS 의존성 없는 별도 SPM 타깃 | [20260712_pure-swift-mode-engine.md](references/20260712_pure-swift-mode-engine.md) |
| 07-12 | Key 표현·픽스처 포맷 | Key는 base+modifiers(shift는 문자에 흡수), 픽스처는 Swift 테이블 | [20260712_key-representation-and-fixture-format.md](references/20260712_key-representation-and-fixture-format.md) |
| 07-12 | pending 무효 시퀀스 no-op | pending 후 무효 키는 둘 다 버림, 타임아웃 없음 (Vim 동일) | [20260712_pending-invalid-sequence-noop.md](references/20260712_pending-invalid-sequence-noop.md) |
| 07-12 | 미매핑 modifier 조합 passthrough | 매핑 없는 Cmd/Ctrl/Opt 조합은 통과 — 시스템 단축키 보존 | [20260712_unmapped-modifier-passthrough.md](references/20260712_unmapped-modifier-passthrough.md) |
| 07-14 | 멀티키 커맨드 문법 빌더 | pending은 부분 파스 상태, resolve는 extend/complete/cancel 스텝 | [20260714_multikey-command-grammar-builder.md](references/20260714_multikey-command-grammar-builder.md) |
| 07-14 | Normal 모드 modifier 탈출 옵션 | 미매핑 콤보는 pending 폐기+Insert 탈출+통과, Ctrl 제외, 기본 on | [20260714_normal-mode-escape-modifiers.md](references/20260714_normal-mode-escape-modifiers.md) |
| 07-17 | 취소 최우선 순서의 전제 | 탈출 콤보 선행은 modifier 매핑 부재가 전제 (Esc swallow는 20260801 부분 supersede) | [20260717_cancellation-first-ordering-premise.md](references/20260717_cancellation-first-ordering-premise.md) |
| 07-24 | Ctrl 매핑 취소 충돌 해소 | 매핑된 Ctrl 콤보만 탈출 판정 제외 — 테이블 파생 단일 소스 | [20260724_ctrl-combo-mapped-exception-cancellation.md](references/20260724_ctrl-combo-mapped-exception-cancellation.md) |
| 07-24 | Ctrl-[ Esc 별칭 | handle() 초입에서 Esc로 치환 — 세 모드 완전 별칭, 엔진 정규화 | [20260724_ctrl-bracket-escape-normalization.md](references/20260724_ctrl-bracket-escape-normalization.md) |
| 08-01 | Normal 빈 상태 Esc는 passthrough | pending 있으면 폐기+swallow, 없으면 통과 — Esc 연타로 앱에 취소 전달 | [20260801_normal-esc-passthrough-when-empty.md](references/20260801_normal-esc-passthrough-when-empty.md) |
| 08-13 | modifier 콤보 swallow 비채택 | 3택 확장 기각(passthrough-only는 토글 off가 이미 제공, swallow는 시스템 단축키 차단) — 2택 유지 + 토글 도움말로 오해 해소 | [20260813_normal-mode-modifier-swallow-not-added.md](references/20260813_normal-mode-modifier-swallow-not-added.md) |
### 엔진 — 출력 계약 (VimAction 어휘)
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-12 | append 전용 Motion 케이스 | a/A는 전용 케이스 — 어댑터가 l·$와 줄 끝 시맨틱 구분 | [20260712_append-dedicated-motion-cases.md](references/20260712_append-dedicated-motion-cases.md) |
| 07-17 | 편집 출력 형태 | .edit(Operator, TextRange) 확정 — 모션 카운트는 반복, 에디트 카운트는 값 | [20260717_vimaction-edit-output-shape.md](references/20260717_vimaction-edit-output-shape.md) |
| 07-19 | change의 Insert 전이 | change 완결 시 엔진 즉시 Insert 전이, cw→ce 특례는 어댑터 몫 | [20260719_change-insert-transition-and-cw-deferral.md](references/20260719_change-insert-transition-and-cw-deferral.md) |
| 07-19 | TextObject quote·pair 확장 | kind 케이스+Scope 연관값, 카운트+오브젝트는 invalid | [20260719_textobject-quote-pair-expansion.md](references/20260719_textobject-quote-pair-expansion.md) |
| 07-19 | linewise TextRange | additive .linewiseMotion — 상대만 카운트, 절대+카운트는 invalid | [20260719_linewise-textrange-absolute-count-invalid.md](references/20260719_linewise-textrange-absolute-count-invalid.md) |
| 07-19 | 오퍼레이터 모션 단일 테이블 | opMotion은 kind 딸린 단일 테이블로 통합, gg만 prefix | [20260719_opmotion-unified-dispatch-table.md](references/20260719_opmotion-unified-dispatch-table.md) |
| 07-22 | Visual 모드 출력 계약 | extendSelection·beginSelection(linewise:)·clearSelection 신설, 앵커·범위는 어댑터 상태 | [20260722_visual-mode-output-contract.md](references/20260722_visual-mode-output-contract.md) |
| 07-22 | Visual 진입 pending 상호작용 | 특례 없음 — 3v는 카운트 무시, dv는 invalid no-op | [20260722_visual-entry-pending-interaction.md](references/20260722_visual-entry-pending-interaction.md) |
| 07-23 | Visual 진입/전환 신호 분리 | beginSelection은 앵커 리셋, v↔V 전환은 switchSelectionWise 신설 | [20260723_visual-begin-reset-switch-wise-split.md](references/20260723_visual-begin-reset-switch-wise-split.md) |
| 07-23 | Visual y의 clearSelection 동반 | y는 [edit(yank), clearSelection] — 잔류 선택 collapse 고정, d/x/c는 미동반 | [20260723_visual-yank-clear-selection.md](references/20260723_visual-yank-clear-selection.md) |
| 07-23 | Visual 카운트+오퍼레이터 실행 | 3d 등 선행 카운트는 버리고 즉시 실행 (Vim 동일) | [20260723_visual-count-operator-executes.md](references/20260723_visual-count-operator-executes.md) |
| 07-23 | openLine(o/O) 출력 계약 | openLine(above:)+Insert 전이, 카운트 무시 | [20260723_openline-output-contract.md](references/20260723_openline-output-contract.md) |
| 07-23 | paste(p/P) 출력 계약 | paste(before:count:) — wise 판정은 어댑터 몫, v1 레지스터 없음 | [20260723_paste-output-contract.md](references/20260723_paste-output-contract.md) |
| 07-23 | undo(u) 출력 계약 | 네이티브 undo 위임, 카운트는 반복 출력, Ctrl-r은 이연 | [20260723_undo-output-contract.md](references/20260723_undo-output-contract.md) |
| 07-24 | 스크롤·redo 출력 계약 | scroll(ScrollExtent, forward:)·redo 신설 — 카운트 반복, Normal 전용 | [20260724_scroll-redo-output-contract.md](references/20260724_scroll-redo-output-contract.md) |
| 07-31 | 카운트 클램프 1,000 하향 | 기준을 "일상 사용 상한"으로 전환 — 폭주 총량 1/10 안전 마진 | [20260731_count-clamp-lowered-to-1000.md](references/20260731_count-clamp-lowered-to-1000.md) |
| 08-01 | D/C 어휘 추가 | d$/c$ 축약 즉시 완결 — 동일 출력, 3D는 invalid | [20260801_line-end-shorthand-d-c.md](references/20260801_line-end-shorthand-d-c.md) |
| 08-01 | 스크롤 카운트 상한 33 | 스크롤만 수십 타 증폭이라 전용 상한 — 클램프 1,000 우회 차단 | [20260801_scroll-count-clamp-33.md](references/20260801_scroll-count-clamp-33.md) |
### 킬스위치·폭주 방어
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-25 | 예외 폭주 자동 off | 시간 주입 순수 카운터(1초/5회), 효과는 소프트 off didSet 재사용 | [20260725_failure-burst-autodisable-shape.md](references/20260725_failure-burst-autodisable-shape.md) |
| 07-26 | 킬스위치 탭은 전용 스레드 | 전용 Thread+자체 CFRunLoop — 메인 스톨 중 배달 보장 | [20260726_kill-switch-dedicated-runloop-thread.md](references/20260726_kill-switch-dedicated-runloop-thread.md) |
| 07-26 | 킬스위치 탭 위치·폴백 | HID 능동 탭 우선 + 세션 폴백, 설치 순서가 계약 (비루트 HID 실측) | [20260726_kill-switch-hid-tap-session-fallback.md](references/20260726_kill-switch-hid-tap-session-fallback.md) |
| 07-26 | 킬스위치 발동 의미론 | 단방향 off + 2겹 효과 + 킬 요청 래치 (오토리핏 가드는 20260801 부분 supersede) | [20260726_kill-switch-trigger-semantics.md](references/20260726_kill-switch-trigger-semantics.md) |
| 07-26 | 실행 실패 보고 단위 | 보고는 원인 키 입력 1건당 최대 1회 — 어댑터가 시퀀스 실패를 폴딩 | [20260726_execution-failure-report-granularity.md](references/20260726_execution-failure-report-granularity.md) |
| 07-26 | 킬 콤보 삼킴은 발동과 독립 | 오토리핏 콤보도 삼킴 (술어 분리·미발동은 20260801 부분 supersede) | [20260726_kill-combo-swallow-independent-of-fire.md](references/20260726_kill-combo-swallow-independent-of-fire.md) |
| 07-26 | 킬스위치 off 영속은 홉과 독립 | 킬 경로 직접 영속 — SIGKILL 생존 실측 | [20260726_kill-switch-off-persistence-off-main.md](references/20260726_kill-switch-off-persistence-off-main.md) |
| 07-26 | 킬 탭 활성화 검증·강등 | tapEnable 뒤 tapIsEnabled 검증, 실패 시 fault + failed 강등 | [20260726_kill-tap-enable-verification.md](references/20260726_kill-tap-enable-verification.md) |
| 07-26 | 미지원 액션은 실패 아님 | 실패 의미론은 "실행 시도 후 깨짐"으로 한정 — 미구현은 스킵+로그 | [20260726_unsupported-action-not-failure.md](references/20260726_unsupported-action-not-failure.md) |
| 07-30 | 실행 중단 래치는 세대 카운터 | beginRun() 세대 비교, 해제 API 없음, 무효화 3주체, 마커 가드 뒤 | [20260730_execution-abort-generation-latch.md](references/20260730_execution-abort-generation-latch.md) |
| 07-30 | 청크 게시 + 페이싱 | 8타 청크·첫 청크 즉시·이후 2ms, 원자 그룹 3종 | [20260730_chunked-posting-with-pacing.md](references/20260730_chunked-posting-with-pacing.md) |
| 08-01 | 킬 콤보 오토리핏도 발동 | shouldFire 제거 — 삼킨 콤보는 전부 발동, 1회성은 래치 test-and-set | [20260801_kill-combo-autorepeat-fires.md](references/20260801_kill-combo-autorepeat-fires.md) |
### 실행 계층 — 배선·매퍼·키 시퀀스
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-25 | Keyboard-first MVP 빌드 순서 | 실행은 Keyboard 어댑터 먼저, AX+auto는 이후 (디스패치 구조 불변) | [20260725_keyboard-first-mvp-build-order.md](references/20260725_keyboard-first-mvp-build-order.md) |
| 07-26 | ActionExecutor 격리·게시 계약 | nonisolated+Sendable, 이벤트는 post 호출자와 같은 직렬 큐에서 생성 | [20260726_action-executor-nonisolated-sendable.md](references/20260726_action-executor-nonisolated-sendable.md) |
| 07-26 | M2 앱 게이트는 엔진 전 통과 | disable 앱은 번역·엔진 전 원본 통과+모드 동결, bundleID는 알림 캐시 | [20260726_m2-app-gate-pre-engine-passthrough.md](references/20260726_m2-app-gate-pre-engine-passthrough.md) |
| 07-26 | M2 실행 배선 형태 | 컨트롤러는 주입된 sink 클로저만 안다, 테스트에선 무해 바꿔치기 | [20260726_m2-execution-wiring-shape.md](references/20260726_m2-execution-wiring-shape.md) |
| 07-26 | 모션 키스트로크 매핑 계약 | 순수 매퍼 Motion→[KeyStroke], 배열 반환이 계약 | [20260726_motion-keystroke-mapping-contract.md](references/20260726_motion-keystroke-mapping-contract.md) |
| 07-26 | w·^(I) 매핑 3타 조합 | 단어 끝 지나친 뒤 시작 복귀 — 수용 엣지 3종 기록 | [20260726_word-forward-first-nonblank-multi-stroke.md](references/20260726_word-forward-first-nonblank-multi-stroke.md) |
| 07-27 | 편집 키스트로크 매핑 계약 | EditKeyMapper (op,range,family)→[KeyStroke]? — Shift 선택 후 오퍼레이터 1타 | [20260727_edit-keystroke-mapping-contract.md](references/20260727_edit-keystroke-mapping-contract.md) |
| 07-27 | linewise 개행 반올림 | delete/yank는 개행 포함·change는 줄 유지, 문서 끝 빈 줄 수용 | [20260727_linewise-newline-rounding.md](references/20260727_linewise-newline-rounding.md) |
| 07-27 | yank collapse는 왼쪽 | Cmd-C 뒤 ← 1타로 범위 시작에 붙임 — 방향 분기 불필요 | [20260727_yank-collapse-to-range-start.md](references/20260727_yank-collapse-to-range-start.md) |
| 07-27 | 오퍼레이터 키 ANSI 고정 | Cmd-X/C는 ANSI 키코드 고정 = QWERTY 가정 (역조회 이연은 20260806 부분 supersede — ANSI는 논리 키코드로 유지) | [20260727_operator-key-ansi-layout-assumption.md](references/20260727_operator-key-ansi-layout-assumption.md) |
| 07-27 | iw 앵커는 단어 끝 경유 3타 | Opt-← 1타는 앞 단어 삭제 위험 — ^와 같은 복귀 패턴으로 교체 (수용 엣지는 20260803 부분 supersede, 3타는 읽기 실패 시 상시 경로) | [20260727_inner-word-anchor-via-word-end.md](references/20260727_inner-word-anchor-via-word-end.md) |
| 07-30 | 명령 매퍼 신설 | CommandKeyMapper(o/O·p/P·u/Ctrl-r·스크롤) — 네이티브 위임 계열, NSPasteboard는 주입 seam | [20260730_command-key-mapper-scope.md](references/20260730_command-key-mapper-scope.md) |
| 07-30 | o/O 시퀀스 | o=Cmd-→,Return / O=Cmd-←,Return,↑ — 수용 엣지 4종 | [20260730_openline-return-sequence.md](references/20260730_openline-return-sequence.md) |
| 07-30 | paste wise 끝 개행 휴리스틱 | 클립보드 끝 개행으로 charwise/linewise, linewise p는 꼬리 보정 | [20260730_paste-wise-trailing-newline-heuristic.md](references/20260730_paste-wise-trailing-newline-heuristic.md) |
| 07-30 | 스크롤은 화살표 반복 | 페이지 키는 죽은 기능(실측) — ↓/↑ 반복(half 15·full 30) | [20260730_scroll-arrow-repetition.md](references/20260730_scroll-arrow-repetition.md) |
| 07-30 | paste wise는 우리 편집을 기억 | 줄 단위 편집을 changeCount와 기억 — 휴리스틱은 외부 복사 전담으로 강등 (기억 대상 한정은 20260806 부분 supersede) | [20260730_paste-wise-from-our-own-edit.md](references/20260730_paste-wise-from-our-own-edit.md) |
| 08-01 | 비-QWERTY 레이아웃 가드 | 행동 검사(Z/X/C/V 번역 확인)로 판별 (통째 보류는 20260806 역조회로 부분 supersede — 가드는 최후 방어선) | [20260801_non-qwerty-command-key-layout-guard.md](references/20260801_non-qwerty-command-key-layout-guard.md) |
| 08-02 | 프로파일 재정의 전파는 조회 전면 | 단일 지점=MotionKeyMapper(옵셔널) — 명령 접두·yank collapse까지 전파, disabled는 복합 통째 스킵 + .disabledByProfile 분류 | [20260802_profile-override-propagation-full-lookup.md](references/20260802_profile-override-propagation-full-lookup.md) |
| 08-06 | paste wise 기억은 편집 전반 | 클립보드 쓰기 편집 전부 기록(change=charwise 포함) — 휴리스틱은 외부 복사 전담, 델타-1 불변 | [20260806_paste-wise-memory-covers-all-edits.md](references/20260806_paste-wise-memory-covers-all-edits.md) |
| 08-06 | `.selection` wise는 확정 스트림 추적 | 게시 확정된 begin/switch의 wise를 PasteWiseResolver가 note — 화면 진실 추적(엔진 확장·앵커 병합 기각) | [20260806_selection-wise-from-confirmed-stream.md](references/20260806_selection-wise-from-confirmed-stream.md) |
| 08-06 | 줄 끝 charwise `p`는 접두 생략 | 읽기가 줄 끝 증명 시 `→` 없이 `Cmd-V` — 줄 끝 커서 모델 네 번째 적용, paste가 읽기 셋째 소비자 | [20260806_charwise-paste-line-end-no-prefix.md](references/20260806_charwise-paste-line-end-no-prefix.md) |
| 08-06 | `.paste` 그룹도 페이싱 | Notion 0간격 버스트가 linewise 접두 화살표를 드롭(로그 판독) — 정확화 그룹과 같은 5ms 대응, 20260805 부분 supersede | [20260806_paste-groups-stroke-pacing.md](references/20260806_paste-groups-stroke-pacing.md) |
| 08-06 | 스크롤 줄 수 우선순위 사다리 | 프로파일 명시값 > AX 뷰포트 > 상수 15/30 (extent별 독립) — 명시 extent는 술어가 읽기 생략 | [20260806_scroll-line-count-priority-ladder.md](references/20260806_scroll-line-count-priority-ladder.md) |
| 08-06 | 뷰포트 줄 수 클램프만·무페이싱 | `min(max(1,n),200)`(파서 상한 정렬·음수 트랩 가드), half=n/2·full=n−2(Vim 겹침), 스크롤 페이싱 없음 유지 | [20260806_scroll-viewport-clamp-no-pacing.md](references/20260806_scroll-viewport-clamp-no-pacing.md) |
| 08-06 | 비-QWERTY 역조회 치환 | KeyTranslator가 z/x/c/v 키코드 역조회 캐시, 어댑터가 게시 직전 6/7/8/9 치환(QWERTY는 생략) — layoutBlocked는 역조회 실패 시 최후 방어선 | [20260806_non-qwerty-command-key-reverse-lookup.md](references/20260806_non-qwerty-command-key-reverse-lookup.md) |
### 실행 계층 — Visual 시퀀스
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-28 | charwise Visual 진입은 1문자 선택 | v는 Shift-→ 1타 즉시 선택 — inclusive 시맨틱 | [20260728_visual-charwise-entry-inclusive-selection.md](references/20260728_visual-charwise-entry-inclusive-selection.md) |
| 07-28 | Visual 확장은 무상태 | extendSelection은 모션+Shift가 전부 — linewise 반올림 미적용 (앵커 상태·linewise 스킵은 20260804 부분 supersede — 무상태는 읽기 실패 폴백 전담) | [20260728_visual-extend-stateless-no-linewise-rounding.md](references/20260728_visual-extend-stateless-no-linewise-rounding.md) |
| 07-28 | switchSelectionWise 반올림 | v→V는 포커스 끝만 반올림, V→v는 역연산 없어 nil 스킵 (20260804 부분 supersede — 앵커 반올림·조건부 V→v, 현행 시퀀스는 폴백) | [20260728_visual-switch-wise-focus-end-rounding.md](references/20260728_visual-switch-wise-focus-end-rounding.md) |
| 07-28 | Visual collapse는 ← 1타 단일화 | clearSelection이 collapse 전담, .selection yank는 Cmd-C만 | [20260728_visual-clear-selection-collapse-left.md](references/20260728_visual-clear-selection-collapse-left.md) |
| 08-04 | Visual 후진은 키보드 재앵커 | 접고 재확장(side 모델) — 후진형은 원점 이동 없음, 크로싱은 수용 엣지, AX 쓰기 기각 (접두는 08-05 단축으로 부분 supersede) | [20260804_visual-backward-keyboard-reanchor.md](references/20260804_visual-backward-keyboard-reanchor.md) |
| 08-04 | 앵커 상태는 게시 큐 협력자 | PasteWiseResolver 동형 주입 — 앵커·wise·side·pid·원캐럿, 수립은 진입 게시 직전 읽기 | [20260804_visual-anchor-state-collaborator.md](references/20260804_visual-anchor-state-collaborator.md) |
| 08-04 | 앵커 무효화는 읽기 자가 검증 | 앵커 쪽 끝+pid 비교, 전용 신호 없음 — 헛실패 방향이 현행 강등이라 안전 | [20260804_visual-anchor-read-self-validation.md](references/20260804_visual-anchor-read-self-validation.md) |
| 08-04 | V→v는 조건부 지원 | 원캐럿+줄 거리 다 알 때만 재선택(위치 상대), 모르면 현행 nil 유지 | [20260804_visual-switch-charwise-conditional.md](references/20260804_visual-switch-charwise-conditional.md) |
| 08-04 | V 세션 charwise 모션은 스킵 | wise 알면 h l w b e 0 ^ $ 무게시(.skipped) — Vim 범위 무변화가 정확, desync는 무해 no-op | [20260804_visual-linewise-motion-range-noop.md](references/20260804_visual-linewise-motion-range-noop.md) |
| 08-05 | 정확화 그룹 한정 스트로크 페이싱 | refined 다타 그룹만 스트로크 사이 5ms(Notion 버스트 드롭 실측) — 스크롤·카운트·폴백은 타이밍까지 현행 (범위는 20260806 paste 추가로 부분 supersede) | [20260805_visual-refined-group-stroke-pacing.md](references/20260805_visual-refined-group-stroke-pacing.md) |
| 08-05 | 재앵커 접두는 collapse 1타 | `←,→`·`←,↓` → `→`(선택 존재 시 동치, 코드 경로 보장) — 깨지는 앱 발견 시 2타 복귀 | [20260805_reanchor-prefix-collapse-shortcut.md](references/20260805_reanchor-prefix-collapse-shortcut.md) |
### 실행 계층 — AX 어댑터 (M5 D1 설계)
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 08-08 | AX 쓰기 통로는 별도 `AXWriter` | 불변식을 "프리미티브당 단일 통로"로 재문언 — seam은 `AXUIElement` 수신·`AXError` raw 반환, 요소는 `AXRead` 경유(50ms 상속) | [20260808_ax-writer-per-primitive-channel.md](references/20260808_ax-writer-per-primitive-channel.md) |
| 08-08 | AX 편집은 선택 + 오퍼레이터 위임 | 범위는 AX 선택(되읽어 검증), 오퍼레이터는 `Cmd-X/C` 1타 위임 — 리치 클립보드·undo 등록 보존, `AXSelectedText` 쓰기 미채택(탈출구만 기록) | [20260808_ax-edit-select-then-operator-delegate.md](references/20260808_ax-edit-select-then-operator-delegate.md) |
| 08-08 | AX 위임 표 + 단일 드라이버 | 명령 매퍼 계열 = 위임(j/k 추가 — 희망 열), openLine·paste 하이브리드, 비텍스트 계열 통째 강등 — 배선은 `Mapping` `.ax`/`.hybrid` 케이스, 액션 all-or-nothing | [20260808_ax-delegation-table-single-driver.md](references/20260808_ax-delegation-table-single-driver.md) |
| 08-08 | AX 실패 보고 화이트리스트·폴백 없음 | D1 실보고는 `.failure`만(`.illegalArgument`는 관측 전용→승격 예약), `.cannotComplete`는 경합 스킵(이중 실행 위험) — 첫 실패 execute 중단, 시각은 게시 큐 캡처 | [20260808_ax-write-failure-whitelist-no-fallback.md](references/20260808_ax-write-failure-whitelist-no-fallback.md) |
| 08-08 | AX 오프셋 계층 — 창+논리 줄 | `FocusedTextOffsets` 순수 함수·AX 전용 확대 반경(4096 잠정)·3상태 반환·unproven은 keyboard 위임 — 논리 줄 `dd` 채택(`dj`≠`d`+`j` 수용), 파라미터화 속성 기각 | [20260808_ax-offset-layer-window-logical-lines.md](references/20260808_ax-offset-layer-window-logical-lines.md) |
| 08-08 | `strategy` 최소 파싱 선행 | D1a에서 accessibility/keyboard 두 값만 파싱 — 임시 배선 기각 (auto 시점·기본값은 20260813 부분 supersede — D2로 이관·auto 전환) | [20260808_strategy-field-minimal-parsing-d1.md](references/20260808_strategy-field-minimal-parsing-d1.md) |
| 08-08 | `.illegalArgument` 관측 로그는 상시 컴파일 | 요약 버킷 관례(`#if DEBUG`+`.debug`)에서 이탈 — 승격 재심사용 사후 회수 판정 데이터, 스킵 2종은 `.debug` 유지 (레벨은 20260814 `.notice` 승격으로 부분 supersede) | [20260808_ax-illegal-argument-observation-log-level.md](references/20260808_ax-illegal-argument-observation-log-level.md) |
| 08-08 | AX Visual 세션 경로 고정 | 진입 시점에 세션 전체 AX/keyboard 고정, 중간 실패는 스킵(무상태 폴백 금지 — 쓰기 후 포커스 끝 미정의) — `VisualAnchorTracker` 공유, AX가 side·pinnedEnd까지 채움 | [20260808_ax-visual-session-path-pinning.md](references/20260808_ax-visual-session-path-pinning.md) |
| 08-08 | AX 모션은 캐럿 모델 유지 | 목표는 현행 keyboard가 겨냥하는 캐럿 자리 그대로(`e`=글자 뒤·`$`=줄 끝·`gg`=0), 정확해지는 것은 RunClass 단어 정의와 `^`뿐 — Vim no-op만 `.invalid`, 블록 커서 모델은 파급 때문에 기각 | [20260808_ax-motion-caret-model-vim-word-definition.md](references/20260808_ax-motion-caret-model-vim-word-definition.md) |
| 08-08 | 프로파일 모션 재정의가 AX보다 우선 | `motions:` 항목이 있으면(strokes·disabled 불문) 그 모션은 keyboard 경로 — 스크롤 사다리와 같은 우선순위, disable의 `.disabledByProfile` 집계가 공짜로 유지된다 | [20260808_profile-motion-override-outranks-ax.md](references/20260808_profile-motion-override-outranks-ax.md) |
| 08-08 | 쓰기 전 단계 실패도 execute 중단 | `.success` 외 **전부**에서 중단(문언 확장) + 요소·읽기 실패는 `.unproven`과 별개 축(`Mapping.axUnavailable`)으로 잔여를 접는다 — Slack류에서 `100j`가 100×50ms로 큐를 잡는 것을 막는다 | [20260808_ax-pre-write-failure-ends-execute.md](references/20260808_ax-pre-write-failure-ends-execute.md) |
| 08-08 | AX collapse는 게시 `←` 유지 | 동기 AX 쓰기가 게시를 **상시 선착** 실측(TextEdit 0/30·Notion 1/30) — yank collapse·`.clearSelection`의 AX 캐럿 쓰기 기각, 정확 선택 위의 `←`가 정확화를 대체 | [20260808_ax-collapse-posted-arrow-not-caret-write.md](references/20260808_ax-collapse-posted-arrow-not-caret-write.md) |
| 08-08 | 되읽어 검증은 수렴 폴링 | Notion은 쓰기 `.success` 후 ~10ms 적용 비동기(실측) — 신선 재읽기·2ms/40ms 폴링·불일치는 스킵+execute 중단·상시 `.info` 버킷, "동기 → 게시" 근거를 마진+검증으로 재문언 | [20260808_ax-readback-verify-convergence-poll.md](references/20260808_ax-readback-verify-convergence-poll.md) |
| 08-08 | 마지막 줄 linewise `p`는 Return 합성 | naive 문서 끝 캐럿은 병합 훼손 실측 — 문서 끝 캐럿 + `[Return, Cmd-V]` 원자 그룹, 끝 개행 1개 편차 수용(P 퇴행 실해소) | [20260808_last-line-linewise-paste-return-synthesis.md](references/20260808_last-line-linewise-paste-return-synthesis.md) |
| 08-08 | AX Visual 재정의 모션은 정직한 스킵 | 재정의 우선 결정 × 무상태 폴백 금지의 교차 — AX 세션에서 그 모션만 스킵(재정의 시퀀스도 무상태 시퀀스), 세션 통째 keyboard pin은 과잉 | [20260808_ax-visual-overridden-motion-honest-skip.md](references/20260808_ax-visual-overridden-motion-honest-skip.md) |
| 08-08 | `unproven` 편집 위임은 AX 창 재사용 | 4096 창 `FocusedText`를 keyboard 정확화에 전달 — 재읽기 없음("한 액션은 한 번만 읽는다"), 술어는 창 상대라 의미 동일 | [20260808_ax-unproven-edit-delegation-reuses-ax-window.md](references/20260808_ax-unproven-edit-delegation-reuses-ax-window.md) |
| 08-08 | 하이브리드 접두+첫 그룹은 원자 | 접두 쓰기(및 검증)와 첫 게시 그룹 사이 중단 질의 없음(전 하이브리드 공통) — 편집의 살아 있는 선택 잔류 창 봉쇄, 원자 그룹 규칙 ④ | [20260808_hybrid-prefix-atomic-with-first-group.md](references/20260808_hybrid-prefix-atomic-with-first-group.md) |
| 08-08 | 접두 실패 문언은 `unproven` 축 전용 | "접두 실패 = keyboard 낙하"의 지시 대상 고정 — 요소·읽기 실패는 `.axUnavailable`, 쓰기 후 실패는 폴백 없음, 문장의 취지는 부분 실행 금지 | [20260808_hybrid-prefix-failure-axes-clarified.md](references/20260808_hybrid-prefix-failure-axes-clarified.md) |
| 08-09 | AX 범위는 표 침묵 자리에서 Vim 정확 | 줄 끝 `dw`·0 이동만 무효(카운트는 클램프) — Vim 실측 14건, 증명 못 하면 `.unproven`. `Insertion`은 `.invalid` 없음 (마지막 줄 흡수는 08-09 클립보드 결정으로 부분 supersede) | [20260809_ax-span-vim-exact-where-table-is-silent.md](references/20260809_ax-span-vim-exact-where-table-is-silent.md) |
| 08-09 | 앞 개행 흡수 철회 — 클립보드가 곧 레지스터 | 흡수하면 잘라낸 내용이 `"\n마지막줄"`이 되어 `ddp`·`yy`·외부 붙여넣기·wise 휴리스틱이 전부 틀린다(도그푸딩 실측) — 빈 줄 1개 잔류(keyboard 패리티)를 택함 | [20260809_no-leading-newline-absorb-clipboard-is-the-register.md](references/20260809_no-leading-newline-absorb-clipboard-is-the-register.md) |
| 08-09 | `Mapping.hybrid`는 다중 그룹 + `paced:` | `.paste`가 카운트만큼 갈리므로 `.groups`와 같은 모양으로 확장 — **원자는 첫 그룹뿐**이고 둘째부터는 공유 청크 루프로 낙하, `paced`는 `.paste`만 참 | [20260809_hybrid-mapping-multi-group-paced.md](references/20260809_hybrid-mapping-multi-group-paced.md) |
| 08-09 | 삽입 하이브리드도 되읽어 검증 | 접두가 캐럿 이동뿐이어도 위임 그룹이 뒤따르므로 비파괴가 아니다(낡은 캐럿의 `Return`은 줄을 쪼갠다) — 액션별로 가르지 않는다(원자 그룹 ④와 같은 논거) | [20260809_hybrid-insertion-readback-verify-kept.md](references/20260809_hybrid-insertion-readback-verify-kept.md) |
| 08-09 | `pasteWise.resolve()`는 순수 조회 | 기억을 소비하지 않음이 감사로 확정 — 매퍼 앞 위치 유지, 게시 확정 부수효과 호출은 액션 무관 단일 지점(`recordEditWise`가 자체 가드) | [20260809_paste-resolve-is-pure-lookup.md](references/20260809_paste-resolve-is-pure-lookup.md) |
| 08-09 | 개행 합성은 `o`/`O`와 같은 두 게이트 | 마지막 줄 `p`의 `Return` 합성은 `.textField`(submit)·`open_line: disabled`(사용자 지시)에서 위임 강등 — `newLineStrokes`의 `nil`이 fail-open 하던 버그 포함, 강등 결과는 현행 `P` 퇴행 | [20260809_newline-synthesis-gates.md](references/20260809_newline-synthesis-gates.md) |
| 08-10 | Visual inclusive 끝은 종결자도 문다 | 세션 1의 "`v$`는 개행을 안 문다"는 마지막 줄 한정 실측이었다 — 비-마지막 줄 레지스터가 `"ab\n"`, `lvl`도 같다. `landsPastCharacter`에 남는 것은 `e` 하나 | [20260810_visual-inclusive-end-bites-terminator.md](references/20260810_visual-inclusive-end-bites-terminator.md) |
| 08-10 | charwise Visual `j`/`k`는 희망 열 추적 | 위임 문언 × 무상태 폴백 금지의 교차 — 포커스 = 줄 시작 + `min(열, 줄 길이)`, `$`는 줄 끝 고정 sentinel, 열 미상은 정직한 스킵 | [20260810_ax-visual-desired-column-tracked.md](references/20260810_ax-visual-desired-column-tracked.md) |
| 08-10 | AX `v`↔`V`는 양방향 정확 지원 | 세션 1이 비워 둔 자리 — 진입이 원래 캐럿을 정확히 읽어 두므로 열이 뺄셈이다. 산출이 범위 + 새 논리 앵커 + 열을 함께 낸다(`Selection`), 상한 32·페이싱 불필요 | [20260810_ax-visual-switch-both-directions-exact.md](references/20260810_ax-visual-switch-both-directions-exact.md) |
| 08-10 | Notion은 AX Visual에 부적합 — 번들 keyboard 유지 | 실측 3건: 앱은 **범위 시작을 앵커**로 봐 후진 확장이 원리적 불가 · Notion은 **블록 넘는 선택을 보고하지 않는다**(화면엔 선택, AX는 `[0,0)`) · 그래서 AX 세션이 블록을 못 벗어난다. 세션 5의 두 예외는 수혜자 부재로 철회. **`strategy` 앱 단위 단일 값의 첫 한계 사례**(편집은 AX·Visual은 keyboard를 표현 못 함 → PR-E) | [20260810_notion-unfit-for-ax-visual-session-5-withdrawn.md](references/20260810_notion-unfit-for-ax-visual-session-5-withdrawn.md) |
| 08-10 | AX Visual 세션 경로는 폐기보다 오래 산다 | pin은 트래커 프로퍼티·진입에서만 쓴다 — 자가 검증 실패 뒤에도 남아 확장·전환이 정직한 스킵(앱 클램프 시 화면에 남은 것이 AX가 쓴 범위라 무상태 폴백은 파괴 방향) | [20260810_ax-visual-session-path-outlives-state-discard.md](references/20260810_ax-visual-session-path-outlives-state-discard.md) |
### 실행 계층 — auto 전략·프로브·force-text (M5 D2 설계)
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 08-13 | `auto` 파싱은 D2에서 | PR-E 배정을 앞당김 — auto 프로브의 유일 소비자가 D2라 파싱 없이는 opt-in 도그푸딩 불가 | [20260813_auto-parsing-in-d2.md](references/20260813_auto-parsing-in-d2.md) |
| 08-13 | 번들 기본 auto 전환은 D2 마지막 단계 | opt-in 도그푸딩 게이트 → 별도 커밋 전환(문제 시 전환만 철회) — `defaultStrategy` 단일 상수, `.empty` 센티널은 keyboard 유지 | [20260813_bundled-default-strategy-auto-flip-gated.md](references/20260813_bundled-default-strategy-auto-flip-gated.md) |
| 08-13 | auto 프로브 — 비동기 캐시, pid 수명 | 별도 협력자 + 전용 큐, 판정 캐시 키 = pid(재시작 = 재프로브, 번들ID/pid 이원 캐시 경합 봉쇄), 트리거는 첫 vim 키 디스패치, 실효 전략은 콜백에서 순수 함수로 접어 DispatchContext 탑재 | [20260813_auto-probe-async-cached-verdict-pid-lifetime.md](references/20260813_auto-probe-async-cached-verdict-pid-lifetime.md) |
| 08-13 | 거짓말 감지 — 읽기·settable 실증 | default-deny 계층(거부 목록→요소 실증→읽기+`IsAttributeSettable`) — 값 변경 왕복 제외(무결성 비용, "판별력 0" 근거는 철회), visible 제외, 선택 진실성 축은 런타임 검출 (신호 3종 전제는 20260818 기하 신호로 부분 supersede) | [20260813_ax-lie-detection-read-attestation-settable.md](references/20260813_ax-lie-detection-read-attestation-settable.md) |
| 08-13 | auto trusted 런타임 강등 + 관측 | `.axUnavailable` 연속 N(잠정 3)이면 pid 수명 강등(무로그 죽은 키 봉쇄 — 검토 3건 수렴), verify 불일치는 관측만(오강등 방지), 관측 3종 + 메뉴바 판정 표시(레벨은 20260814 `.notice` 승격), 프로파일 명시 권고 안내는 PR-E 문서 | [20260813_auto-trusted-runtime-demotion-and-observability.md](references/20260813_auto-trusted-runtime-demotion-and-observability.md) |
| 08-13 | AX 신뢰 거부 목록 | 코드 상수 `{notion.id}` — 등재 기준은 "신호가 못 잡음이 실측된 거짓말", auto에만 적용(명시 accessibility가 이김 + override `.info`), YAML 비노출 (계층 1 단일 목록 전제는 20260818 브라우저 클래스로 부분 supersede) | [20260813_ax-trust-deny-list-code-constant.md](references/20260813_ax-trust-deny-list-code-constant.md) |
| 08-13 | force-text — 자동 폴백 없음·치환은 keyboard 쪽만 | 20260712 유지 확인 + `keyboard_family: key_mapping\|force_text`(snake_case) — 실효 family 치환은 걸러내기·매퍼·위임분만, `usesAXWrite`·AX 강등은 원본 family(AX로 새면 비텍스트에 AX 쓰기) | [20260813_force-text-keyboard-family-substitution.md](references/20260813_force-text-keyboard-family-substitution.md) |
| 08-13 | AX Visual `.selection` 편집 위임 가드 | `Cmd-X`/`Cmd-C` 위임 직전 선택 재검증 1회(기존 술어 재사용) — 앱의 범위 재정규화 위 파괴 경로 봉쇄, "다음 Visual 액션 검증"이 파괴 단계 앞에서만 비던 구멍 | [20260813_visual-selection-edit-pre-delegation-guard.md](references/20260813_visual-selection-edit-pre-delegation-guard.md) |
| 08-13 | `.illegalArgument`·`.cannotComplete` 재심사 종결 | 관측 전용·경합 스킵 유지 — 세션 0 전수 실측 재현 불가(~550+121회·~580회 전부 0건), 관측 로그는 유지 | [20260813_illegalargument-cannotcomplete-observation-kept.md](references/20260813_illegalargument-cannotcomplete-observation-kept.md) |
| 08-13 | Electron 트리 기상 채택 — pid당 1회 | `AXManualAccessibility=true` + 유계 재시도, 첫 vim 키 앱에만(비례성) — 기존 "Slack·VS Code 미노출"은 수면 상태 측정(순환 반증), 기상 Slack은 왕복 10/10 "AX 신뢰 가능" (트리거·재시도는 20260814 부분 supersede) | [20260813_electron-tree-wake-on-probe-failure.md](references/20260813_electron-tree-wake-on-probe-failure.md) |
| 08-14 | 메뉴 판정 pid는 게이트 비자신 짝 | `lastNonSelfProcessID` — 번들과 한 짝 갱신(가드 앞·시드 단일 조회), 메뉴 열림의 자기 pid 오표시 봉쇄, 디스패치 경로는 계속 리졸버 pid | [20260814_menu-verdict-pid-from-gate-non-self-pair.md](references/20260814_menu-verdict-pid-from-gate-non-self-pair.md) |
| 08-14 | Visual 가드 불일치 로그는 상시 관측 | 재검토 조건("가드 불일치가 잦으면 수렴 폴링 재검토")의 판정 데이터 — 릴리스 도그푸딩에서 회수 가능해야 해 illegalArgument 전례 적용, 읽기 실패 스킵은 DEBUG 유지 (레벨은 같은 날 `.notice` 승격으로 부분 supersede) | [20260814_visual-guard-mismatch-log-info.md](references/20260814_visual-guard-mismatch-log-info.md) |
| 08-14 | 프로브 기상은 콜드 형태 실패 전반 + 백오프 | 도그푸딩 실측 — Chromium auto-disable은 "요소는 보이는데 읽기만 콜드"인 반콜드로 나타나 기존 트리거(요소 실증 한정)로는 기상 불발·프로브 2회 연속 탈락. 기상 실행은 예산 4회·200/400/800/1600ms 백오프 | [20260814_probe-wake-on-cold-form-and-backoff.md](references/20260814_probe-wake-on-cold-form-and-backoff.md) |
| 08-14 | 사후 판독 관측은 `.notice` + 프로브 완료 로그 | macOS는 `.info`를 영속하지 않음이 실측됨(도그푸딩 하루치 증발) — 관측 세트 전부 `.notice` 승격(Bool+번들 ID뿐이라 무해, 지원 흐름 겸용), untrusted 프로브 완료는 신호 Bool 4종+기상+재프로브 횟수 1줄 | [20260814_observation-notice-promotion-and-probe-completion-log.md](references/20260814_observation-notice-promotion-and-probe-completion-log.md) |
| 08-18 | 브라우저 클래스는 auto 불신 — 계층 1 동적 축 | https 핸들러 등록 앱(LaunchServices)은 AX 접촉 없이 untrusted(`.browser` 종단, 명시 accessibility가 이김) — pid 판정이 브라우저의 URL바/웹 콘텐츠 이질성을 못 담음이 실측(Arc URL바 trusted → Docs 조용한 거짓말), per-element는 PR-E 이월 | [20260818_browser-class-auto-untrusted.md](references/20260818_browser-class-auto-untrusted.md) |
| 08-18 | 숨은 입력은 기하로 걸러냄 — `AXSize` 짧은 변 <4pt | 프로브 신호 5종(요소·기하·읽기·settable), `.geometry` 탈락은 확정 답변(재시도·기상 없음) — Docs 숨은 contenteditable 625×1pt가 신호 3종·안전망 2겹 전부 통과함이 실측, VS Code(800×23, 정직)는 무영향 | [20260818_hidden-input-geometry-signal.md](references/20260818_hidden-input-geometry-signal.md) |
### 수용 엣지 — 도그푸딩 실측 (대부분 M4 프로파일·M5 AX가 해소 예정)
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-26 | Shift 새어 들어감 종결 | 이벤트 flags 명시 대입으로 충분 — 전역 채널 기각, 재발 시 재개 | [20260726_shift-leak-event-flags-sufficient.md](references/20260726_shift-leak-event-flags-sufficient.md) |
| 07-26 | 탭 들여쓰기 ^·I 엣지 | Chromium 계열 퇴행 수용 — 고정 시퀀스 부재, M5 AX 해소 | [20260726_tab-indent-first-nonblank-chromium-edge.md](references/20260726_tab-indent-first-nonblank-chromium-edge.md) |
| 07-26 | undo 단위 실측 — u=Cmd-Z 유지 | 합성 시퀀스는 1 undo 단위 실증, change만 분리 수용 | [20260726_undo-unit-cmdz-policy.md](references/20260726_undo-unit-cmdz-policy.md) |
| 07-27 | Notion Shift-Cmd-↑/↓ 충돌 수용 | 블록 이동 충돌로 6조합 파괴적 오동작 — M4 프로파일이 해소 | [20260727_notion-cmd-shift-vertical-conflict.md](references/20260727_notion-cmd-shift-vertical-conflict.md) |
| 07-28 | linewise 시각 줄 엣지 | 소프트 랩에서 dd/cc가 화면 행 단위 — keyboard 경로 한정으로 유효(AX 경로는 20260808 논리 줄로 부분 supersede) | [20260728_linewise-visual-line-wrap-accepted-edge.md](references/20260728_linewise-visual-line-wrap-accepted-edge.md) |
| 07-28 | charwise Visual 후진 원점 이동 | 진입 Shift-→가 원점을 P+1로 — vb·vh 빈 선택 (수용 결정은 20260804 재앵커로 부분 supersede — 읽기 실패 폴백만 잔존) | [20260728_visual-charwise-backward-origin-shift.md](references/20260728_visual-charwise-backward-origin-shift.md) |
| 08-06 | Slack 스크롤 화살표 컴포저 이탈 수용 | `↑` 포화 후 메시지 선택 이동은 Slack 네이티브 동작 — 코드 특례 없음, 아프면 사용자 프로파일 몫 | [20260806_slack-scroll-arrow-composer-escape-accepted.md](references/20260806_slack-scroll-arrow-composer-escape-accepted.md) |
| 08-08 | 마지막 줄 linewise `p`는 `P`로 퇴행 | `→` 문서 끝 포화 + 멱등 보정자의 교환(훼손 대신 위치 오차) — `ddp`에서 재현, keyboard 경로에선 미해소·D1b `.paste` 하이브리드가 포화 자체를 없앤다 | [20260808_last-line-linewise-paste-degrades-to-P.md](references/20260808_last-line-linewise-paste-degrades-to-P.md) |
### 전략 디스패치·요소 리졸버
| Date | Title | 요약 | Reference |
|---|---|---|---|
| 07-12 | AX/Keyboard 전략 디스패치 | 앱별 프로파일 + AX 자동 감지로 전략 선택, force-text는 명시 전용 | [20260712_ax-keyboard-strategy-dispatch.md](references/20260712_ax-keyboard-strategy-dispatch.md) |
| 08-01 | TextField 전용 편집 시퀀스 폐기 | .textField도 TextArea 시퀀스 — 전용 분기는 role 오보고 시 개악 | [20260801_textfield-edit-sequences-scrapped.md](references/20260801_textfield-edit-sequences-scrapped.md) |
| 08-01 | 리졸버 폴백은 .textArea | AX 실패·타임아웃·미지 role은 전부 .textArea — 걸러내기는 확실할 때만 | [20260801_resolver-fallback-defaults-to-text-area.md](references/20260801_resolver-fallback-defaults-to-text-area.md) |
| 08-01 | 계열 판별자는 AXSelectedTextRange 노출 | role 화이트리스트 붕괴(실측) — 속성 이름 목록만 유효, role은 Area/Field 구분만 | [20260801_element-family-classification-table.md](references/20260801_element-family-classification-table.md) |
| 08-01 | focusedRole 캐시 — AX는 메인 밖 | 읽기는 전용 큐 50ms(3ms 캡은 콜드 6/6 실패), 계열은 키 입력 시점 스냅샷 | [20260801_focused-role-cache-shape.md](references/20260801_focused-role-cache-shape.md) |
| 08-01 | 앱 전환 직후는 미확정 창 | 레이스 실증 — 4번째 케이스 .unresolved, 걸러내기는 nonText와 같은 편 | [20260801_unresolved-window-after-app-switch.md](references/20260801_unresolved-window-after-app-switch.md) |
| 08-01 | 캐시 충분성 1차 확정 | 라이브 AX 읽기 필요 케이스 없음 — 갱신 2경로 실측, M5에서 재확인 | [20260801_cache-only-callback-confirmed-sufficient.md](references/20260801_cache-only-callback-confirmed-sufficient.md) |
| 08-01 | 비텍스트 걸러내기 범위 | .nonText 스킵은 편집·Visual·명령 위임만 — move·scroll 유지, 게이트는 어댑터 1곳 | [20260801_non-text-filter-keeps-motion-and-scroll.md](references/20260801_non-text-filter-keeps-motion-and-scroll.md) |
| 08-02 | 디스패치 경로 AX 읽기 형태 | 게시 큐 위 lazy 읽기(콜백·메인 무접촉 유지), 창 프리미티브(AXValue 전체 금지), 실패는 무상태 폴백 | [20260802_dispatch-read-on-posting-queue.md](references/20260802_dispatch-read-on-posting-queue.md) |
| 08-02 | AX 타임아웃 50ms 단일 상수 | 3ms 캡 supersede(웜 Notion 16ms 실측) — 탭을 지키는 건 캡 값이 아니라 배치, 실패 반환 캡+2ms 바운드 확인 | [20260802_ax-read-timeout-50ms-supersedes-3ms.md](references/20260802_ax-read-timeout-50ms-supersedes-3ms.md) |
| 08-02 | 캐럿 주변 읽기 API 모양 | `FocusedText` 4필드(`windowRange` 필수), 창 ±256 고정, pid 출처는 리졸버(게이트 아님), 실패는 액션 단위로 기억되는 단일 nil | [20260802_focused-text-read-api-shape.md](references/20260802_focused-text-read-api-shape.md) |
| 08-02 | 읽기 소비는 매퍼 술어 2함수 | `keyStrokes`에 text를 넣지 않는다(nil 의미 중첩·classify 3프로브·사유 모르는 자리의 로그) — `consultsFocusedText`/`collapsesToNothing`이 값을 받고, cw 리타깃은 시퀀스와 같은 함수를 공유 | [20260802_read-consumption-via-mapper-predicates.md](references/20260802_read-consumption-via-mapper-predicates.md) |
| 08-02 | 0폭 포화 편집 억제 (엣지 5 해소) | 증명된 6종만 액션 통째 스킵(`.skipped` 재사용), 카운트 규칙 없음 — w·^·줄 경계·`.selection`은 각각 다른 이유로 보류 (charRight/문서 끝 행은 20260803 부분 supersede) | [20260802_empty-selection-edit-suppression.md](references/20260802_empty-selection-edit-suppression.md) |
| 08-03 | 재조립은 분기의 근거만 (레이스) | 읽기로 시퀀스를 고르되 스트로크 수는 정하지 않는다 — 낡은 읽기의 최악이 현행 동작을 넘지 않게, 오프셋 비례 스트로크 금지 | [20260803_refinement-branches-not-stroke-counts.md](references/20260803_refinement-branches-not-stroke-counts.md) |
| 08-03 | `keyStrokes(text:)` + 3-프로브 | 재조립이 시그니처를 바꾼다 — `collapsesToNothing` 접힘, 편집 전용 `classifyEdit`이 프로브 순서를 구조로 강제(텍스트→builtIn, builtIn은 text 미수신) | [20260803_edit-keystrokes-takes-focused-text.md](references/20260803_edit-keystrokes-takes-focused-text.md) |
| 08-03 | 경계 포화 정확화 표 (엣지 2·3·4·`^`) | 첫 줄 `dk`·첫 비공백 `^`는 무효 스킵, 마지막 단어 `dw`는 `e` 1타, 마지막 줄 `dgg`는 `cgg` 접두 재사용 — 읽기를 묻는 범위는 최소로만 확장 | [20260803_boundary-saturation-refinement-table.md](references/20260803_boundary-saturation-refinement-table.md) |
| 08-03 | 줄 끝 charwise = Vim 커서 모델 (엣지 1) | 줄 끝 `x`는 `Shift-←`로 마지막 글자 삭제(그 한 자리로 범위 한정), 빈 줄은 무효, 아니면 clamp — 문서 끝 억제를 덮어씀. 유일하게 "현행 이하"가 아닌 재조립 (모션 밖 확대 금지 한정은 20260803 단어 어휘로 부분 완화) | [20260803_line-end-charwise-vim-cursor-model.md](references/20260803_line-end-charwise-vim-cursor-model.md) |
| 08-03 | 소프트 랩은 창 읽기로 해소 불가 | 증명 실패(랩 문단 > 창 반경)·중단 불가 원자 그룹·낡은 오프셋 셋 — 수용 엣지 유지, `dd`·`dj`는 읽기 0건. 단락 바인딩 실측이 재개 조건 | [20260803_soft-wrap-linewise-not-resolved-by-window-read.md](references/20260803_soft-wrap-linewise-not-resolved-by-window-read.md) |
| 08-03 | 단어 질의는 로컬 술어 (오프셋 없음) | Vim 런 4클래스(blank/keyword/punctuation/other, 개행은 종결자) + 캐럿 ±1자 술어 3종 — 오프셋을 안 쓰니 `Opt-→` 정합·잘린 단어 난점이 소멸 | [20260803_word-run-local-predicates-no-offsets.md](references/20260803_word-run-local-predicates-no-offsets.md) |
| 08-03 | `iw`·`cw` 재조립은 상수 1타 | 스트로크 수 원칙 예외 없이 유지 — 1자 런/런 끝만 1타로 정확화, 낡은 읽기 최악이 현행보다 작아지고 원자 그룹도 4타→2타. `cw`와 진짜 `ce`·`de`는 리타깃 플래그로 갈림 | [20260803_constant-stroke-word-refinement.md](references/20260803_constant-stroke-word-refinement.md) |
| 08-03 | 줄 끝 커서 모델을 `iw`·`cw`로 완화 | 줄 끝 = 커서가 마지막 글자 위 — `iw`는 `Shift-Opt-←`(키워드 한정), `cw`는 `Shift-←`. 완화가 단어 어휘 안에서 닫히는 것이 근거(모션은 캐럿 모델 유지) | [20260803_line-end-cursor-model-for-word-objects.md](references/20260803_line-end-cursor-model-for-word-objects.md) |
| 08-06 | 뷰포트 줄 수는 `AXLineForIndex` 차 | visible 양 끝 표시 줄 번호 차 — 화살표 단위와 일치(소프트 랩 정확, 개행 세기는 6× 과소 기각), 문서 전체 가시는 오보 가드(`provenViewport`)로 폴백 | [20260806_viewport-lines-via-line-for-index.md](references/20260806_viewport-lines-via-line-for-index.md) |
| 08-06 | 뷰포트 스냅샷은 execute당 1회 | "액션마다 새로" 계약의 명시적 이탈 — 뷰포트 높이는 버스트 불변, 액션별 재읽기는 이득 0에 최악 33×50ms | [20260806_viewport-snapshot-per-execute.md](references/20260806_viewport-snapshot-per-execute.md) |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!