Repository navigation
Closed
Labels
documentationImprovements or additions to documentationImprovements or additions to documentation
Description
Goal Anchor
- Outcome: 레포에 모인 앱·편집 사례와 오랫동안 정착한 편집 관습에서, 장기간 호환성을 지킬 최소 개념·공통 불변 조건·profile별 차이·책임 하이라키를 도출한 설계 초안을 만든다.
- Done: 사례 → 외부 근거와 반례 → 공통 계약 또는 profile 선택 → 기존 책임과의 연결을 검토할 수 있는 문서로 정리한다. 확정할 수 있는 결론과 아직 동결할 수 없는 질문을 구분하고, 이슈 댓글에는 학습에 필요한 근거·대안 비교·판단 요약·검증 결과·원문 자료를 남긴다.
- Don't: runtime 구현, 공개 API, Stable profile, package 배치를 변경하지 않는다. 새 범용 editor·command bus·profile registry를 도입하지 않는다. 조사 결과를 표준 완성이나 독립 구현 간 상호운용 인증으로 주장하지 않는다.
사용자에게 위임받은 설계 범위
사용자는 편집 문법을 이미 장기간 정착한 사실상 표준으로 보고, 여러 앱과 개념을 모아 그 공통 문법을 도출하려 한다. “디테일 전에 프로토콜과 하이라키를 먼저” 정하고 “30분 정도 알아서 진행”하도록 요청했다. 이어 “과정을 학습할 수 있게 이슈와 댓글”에 공부할 내용을 남기도록 요청했다.
이 작업의 산출물은 설계 초안이다. 기존 논의에서 나온 대상·선택·focus·편집 맥락, 편집 행위, 작업 경계, 결과·복원은 검증할 후보이며 새 API로 확정한 목록이 아니다. 앱별 기능의 합집합을 Core로 옮기는 것으로 해석하지 않는다. 특히 한 앱 안에서 객체·셀·내부 텍스트 편집이 중첩되는 사례를 살펴본다.
기존 자산과 경계
standards/editing-grammar.md: 공통 규칙 EG-SELECT부터 EG-RESULT, profile별 결정, 적합성 증거와 장기 호환성을 연결하는 기존 Design Draft. 이번 초안도 이 정본 설계 문서를 발전시킨다.json-document의 여섯 member, Selection family, Editing session/history, 각 editor와 플랫폼 adapter의 기존 책임을 근거로 삼는다.- Document·Rich Text·Order·Tree·Sheet·Database·Object·Kanban·Calendar·Annotation·Composer를 편집 사례로 조사한다. 같은 내부 구현 기반의 여러 사례를 독립 생태계 구현 증거로 세지 않는다.
- 외부 근거는 역사적 편집 지침, 현재 제품의 공식 동작 문서, W3C의 관련 명세·구현 지침을 구분해 사용한다. 단축키 일치와 의미 계약 일치를 구별한다.
- 편집 문법의 공통 규칙과 Hands profile을 적합성 테스트로 연결한다 #721 / #722의 적합성 구현과 Document의 동일 블록 내 offset 선택과 범위 확장을 반영한다 #723 / #724의 선택 보존 수정은 기존 자산이다. 이번에는 새 동작을 추가하거나 미구현 사례를 완료했다고 표시하지 않는다.
검토 가능한 완료 증거
- 편집 사례별 대상·위치·선택·행위·중첩 맥락과 차이를 읽을 수 있다.
- 공통 후보마다 근거와 반례 또는 성립 조건이 있고, 공유 의미와 profile 정책을 구분한다.
- 의미의 분류, 계약의 구체화 관계, 실제 구현 의존 관계를 혼동하지 않는 하이라키를 제시한다.
- 기존 EG 규칙·owner·적합성 증거와 연결하며, 새로 도출한 사항의 실행 검증 여부를 명시한다.
- 문서 검사와 전체 diff 검토를 마치고 문서 PR로 제공한다. 조사 단계별 학습 댓글에는 확인 가능한 출처와 판단 요약을 남긴다.
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentationImprovements or additions to documentation
Activity
developer-1px commentedon Sep 7, 2026
작업 계획과 읽는 방법
이슈 본문의 Goal Anchor를 기준으로, 사례와 정착한 관습에서 최소 편집 계약·profile 차이·하이라키를 도출한다. 완료 증거는 근거와 반례가 연결된 설계 초안과 검증된 문서 PR이다. runtime·공개 API·Stable profile·package 배치는 그대로 유지한다.
댓글마다 확인한 사실, 설계 후보와 판단 요약, 기각한 대안, 검증 결과, 다음 질문을 기록한다. 구현 완료 여부와 새 제안의 검증 여부를 구분한다. 독자가 원문과 코드를 보고 결론을 재검토할 수 있는 학습 기록을 목표로 한다.
학습의 첫 질문은 **같은 Delete가 문자 제거·셀 값 비우기·행 제거로 달라져도 무엇이 같은 편집 문법인가?**이다. 단어 목록의 교집합만 뽑으면 이 차이를 잃고, 기능의 합집합을 만들면 작은 Core를 잃는다. 대상과 결과의 관계를 먼저 살펴본다.
검증은
docs:evaluate, 문서 링크·코드 근거 확인, 전체 diff의 범위·모순 검토로 한다. 현재 문서만 변경하므로 새 runtime 테스트나 브라우저 인증을 완료 증거로 대신하지 않는다. 기존 적합성 테스트는 문서에 연결된 현재 증거를 확인할 때 사용한다.관찰된 위험은 두 가지다. 여러 내부 editor가 공통 Session을 쓴다는 사실을 독립 구현의 합의로 오해할 수 있고, 현재 구현의 제한을 영구 표준으로 굳힐 수 있다. 각 사례의 증거 수준과 반례를 함께 기록해 판별한다.
developer-1px commentedon Sep 7, 2026
학습 1 — 오래된 명령을 찾는 것과 오래된 의미를 찾는 것은 다르다
관찰. Apple의 1992년 Macintosh Human Interface Guidelines는 선택 후 작업하는 관습을 설명하면서도 텍스트·배열·그래픽 선택을 구분한다. 특히 표의 필드 전체를 다루는 경우와 필드 안의 텍스트를 편집하는 경우를 구별한다. Windows의 표준 Edit 메뉴에도 Undo/Redo·Cut/Copy/Paste·Delete·Select All이 반복된다.
이 자료들은 사용자의 “이미 정착한 편집 문법을 도출한다”는 출발점을 뒷받침한다. 다만 모든 앱의 정확한 단축키·삭제 방식·Undo 묶음까지 30년간 동일했다는 증거는 아니다.
레포에서 확인한 차이. Sheet의 Cut은 primary rectangle의 값을
null로 비우고 셀 구조를 유지한다. Database의record.delete는 record를 제거한다. Document의 Copy는 블록 전체이고 Rich Text는 structured slice다. 같은 동사라도 대상과 결과를 빼면 계약을 설명할 수 없다.설계 판단. 프로토콜의 단위는 명령 이름만이 아니라
작업을 받을 편집 맥락 + 대상/위치 + 의도 → 관찰 가능한 결과여야 한다. 이 표기는 설명을 위한 문법이며 새 command envelope API 제안은 아니다.기각한 대안. 앱별 메서드를 하나의 전역 union으로 합치는 방식은 Delete/Clear, 구조 선택/내부 텍스트 선택의 차이를 가린다. 각 앱의 기능 목록을 Core에 계속 추가하는 방식도 장기 약속의 범위를 불필요하게 키운다.
읽을 자료와 확인할 질문.
cut과record.delete가 실제로 바꾸는 값을 비교하면 차이가 보인다.다음 검토는 이 공통 후보가 성립하지 않는 편집기를 찾는 것이다. 반례는 설계의 실패를 숨길 이유가 아니라, 영구 계약의 범위를 정할 증거다.
developer-1px commentedon Sep 7, 2026
학습 2 — 반례로 공통 규칙의 적용 범위를 좁히기
관찰한 반례.
annotation.create는 새 annotation을,event.create는 시간 구간을 직접 받는다판단. “내용을 바꾸지 않는다”와 “History에 남기지 않는다”는 서로 다른 명제다. 현재 EG-SELECT/EG-HISTORY는 레포의 기존 Selection·Editing 동작을 설명하고 실제 테스트가 있다. 이 계약을 깨지 않고 적용 범위를 명시할 수 있다. GIMP를 같은 profile이라고 선언하거나, 반례를 수용한다며 기존 테스트의 의미를 바꾸지는 않는다.
기각한 대안. 예외를 전부
Host-specific으로 밀어내면 사람이 이미 사용하는 편집 문법을 프로토콜에서 잃는다. 반대로 모든 차이를 즉시 Core의 새 기능으로 수용하면 공통 계약이 기능 목록이 된다. 의미가 다른 경우 profile의 성립 조건으로 설명하고 그 owner에서 검증할 질문을 남기는 편이 맞다.공부할 자료.
Option-Command-V의 Finder 이동 의미를 텍스트 편집의 같은 키 조합과 비교할 수 있다.selection.set과annotation.create의 입력을 비교해 볼 수 있다.이번 관찰은 새 raster/file editor를 구현하자는 범위 확장이 아니다. 기존 11개 사례만으로 보편성을 주장할 수 없음을 드러내는 외부 반례다.
developer-1px commentedon Sep 7, 2026
학습 3 — 하이라키에서 ‘종류’, ‘조합’, ‘의존’을 구별하기
관찰. APG Grid는 셀 탐색과 내부 caret 조작을 구분한다. Keynote도 텍스트 상자 자체를 선택하는 상태와 내부 글을 편집하는 상태를 구분한다. 레포에서는
DocumentTextControl이 native range를 투영하고,registerWebVirtualSelectionScope는 전체 텍스트 선택·Copy 영역과 editable target 우선 처리를 맡는다. 부분적인 소유자는 이미 존재한다.설계 후보.
이것은 계약이 구체화되는 관계다.
Core → Editing → Hands → App처럼 읽는 순서나 package import graph만으로 이 관계를 대신할 수 없다. Sheet가 Rich Text를 상속하는 것도 아니고, 셀 편집을 시작할 때마다 별도 History를 만들어야 한다는 뜻도 아니다.분리해서 남긴 용어.
focus: 범위의 한 endpoint.scope: "this" | "this-and-following" | "all": 반복 일정의 변경 범위. 입력을 받을 편집 맥락과 다르다.기각한 대안. 모든 중첩을 범용
Scope클래스 하나로 선언하면 DOM focus, model subtree, History 귀속을 우연히 묶을 위험이 있다. 이번에는 실제 필요한 진입·수신자·거절·복귀 규칙을 사례로 명시하고 새 runtime 추상화는 만들지 않는다.검증할 반례. 내부 text editor가 Delete를 거절했을 때 바깥 객체가 삭제된다면, 두 editor 각각의 단위 테스트가 통과해도 조합 계약은 실패한다. 따라서 현재의 원자적 편집 테스트와 별도로 중첩 수신자·실패 전파를 관찰해야 한다. 이번 문서에는 이 사례를 미실행 후보로 표시한다.
읽을 자료.
developer-1px commentedon Sep 7, 2026
학습 4 — 근거의 강도와 설계의 강도를 맞추기
외부 자료와 내부 구현을 비교한 결과를 다음처럼 구분했다.
ScopeAPI 채택 근거는 아님초안 리뷰에서 보완한 점. Tree의 실제 코드를 확인하니 Copy와 제거는
descendantClosure로 숨은 후손까지 포함한다. 따라서 “편집은 보이는 선택만 바꾼다”는 규칙은 부적절하다. Selection과 실제 작업 대상·영향 범위를 구별하도록 표를 고쳤다. Calendar의 반복 범위도 같은 구별이 필요하다.현재 EG 규칙을 바꾸는 대신 적용 범위를 명시했다. 범위 확장의 anchor 규칙은 anchor를 가진 family에 적용하고, 현재 즉시 제거하는 Cut을 Finder 같은 지연 이동의 규칙이라고 주장하지 않는다. 기존 profile의 약속은 유지하며 공통 규칙의 보편성 주장을 좁히는 것이 이번 설계 수정이다.
작게 유지하는 기준. Profile이라는 말로 모든 결정을 자유롭게 남겨 두면 표준이 되지 않는다. 하나의 profile revision 안에서는 대상·작업·결과·실패·History 경계의 답이 고정되어야 한다. 공통 규칙이 답을 정하는 항목과 profile이 답을 채우는 항목을 구별하고, 채운 답을 이전 vector로 계속 검증해야 한다.
검증 현황.
docs:evaluate통과. 설계 문서의 내부 Markdown 링크 28개 대상 존재 확인, code fence 5개 균형 확인. 새 사례는 미실행 후보로 명시했다. Runtime·공개 API·기존 behavior vector는 변경하지 않았다.다음 판정. 기존 적합성 증거를 재실행하고 최종 diff를 이슈의 완료 조건과 대조한다. 문서의 분량 증가 비용을 줄이기 위해 중복된 책임 흐름 그림은 하나로 합쳤다.
developer-1px commentedon Sep 7, 2026
학습 5 — 초안을 검증 가능한 약속으로 바꾸는 마지막 검토
원문을 다시 대조하니 Apple HIG 1992 인쇄 쪽수 290–291에도 Shift-click 확장의 addition과 fixed-point 방식이 함께 나온다. 그래서 EG-SELECT의 anchor 보존을 “anchor가 있는 모든 범위 선택”에 적용한다고 읽힐 문장을 현재의 고정 anchor 전이로 좁혔다. 기존 EG 문장과 구현을 바꾼 것은 아니다. 학습 1의 PDF 뷰어 쪽수 안내도 1부터 세는 쪽수 기준으로 바로잡았다.
이 사례가 보여주는 검토 방법은 다음과 같다.
대안 비교의 결론. 기존 구현 이름만 하나로 합치면 의미의 차이가 사라지고, 모든 차이를 Host 정책으로 남기면 재사용 가능한 약속이 사라진다. 이번 초안은 공통 의미와 profile에서 채울 답을 구분하고, 그 답의 정본 owner를 유지한다. 새 기능이나 범용 scope runtime을 추가하지 않은 이유도 여기에 있다.
검증 결과. 공통 적합성 5 files / 51 tests 통과. 문서 검사·내부 링크·전체 diff 검토 통과. 기존 EG 규칙 9개와 owner 표를 보존했고 변경 파일은
standards/editing-grammar.md하나다. 최종 원문 대조에 따른 설명 보완도 같은 문서 범위에서 처리했다.PR #726에 검토할 설계가 있다. 현재 단계는 문서 PR이며 merge나 Stable admission을 완료한 상태가 아니다. 중첩된 편집의 진입·거절·복귀, profile 간 교환, 여러 편집 맥락의 History 귀속은 문서의 검증 질문으로 남아 있다.
developer-1px commentedon Sep 7, 2026
결과와 학습 순서
PR #726에 설계 초안을 정리했다. 최종 commit은
c8570dc7이며 CI Plan·Package·Site가 통과했다. External kit은 이번 변경에 대한 실행 계획에서 skipped다. 문서 검사, 기존 공통 적합성 51개 테스트, 내부 링크 28개와 GitHub 렌더링의 표 10개·코드 블록 5개도 확인했다.이 순서로 읽으면 설계가 어떻게 도출됐는지 따라갈 수 있다.
최종 설계 문서는 11개 사례 → 최소 질문 → 중첩과 반례 → 하이라키 → 기존 EG·owner·적합성 → 새 검증 질문 순서로 읽을 수 있다.
본문의 완료 조건은 모두 설계 초안과 검증 결과에 연결했다. Runtime·public API·Stable profile·package 배치 변경은 없고, 기존 EG 규칙 9개와 owner 표를 보존했다. 원래 checkout의 작업 파일은 보존하고 별도 clone의
issue-725-editing-grammar-derivation에서 작업했다.현재 상태는 pr-open이다. 설계 작업은 마쳤으며 merge와 표준 동결은 별도 단계다. 남은 설계 질문은 중첩 편집의 진입·거절·복귀, profile 간 payload 교환, raster/file 적용 범위, 여러 편집 맥락의 History 귀속이다. 이 질문들을 구현 완료로 표시하거나 후속 구현 이슈로 자동 확대하지 않았다.
developer-1px commentedon Sep 7, 2026
추가 조사 — 조합 경계를 30분 더 살펴보기
사용자가 “30분만 더 조사 위주로 진행해 지금처럼 이슈에다가 읽을 거리 주는 식으로” 요청했다. 앞의 설계 초안과 학습 기록을 이어서, 다음 질문을 조사한다.
대상은 인간의 편집 동작과 이를 연결하는 protocol이다. 1차 비교 대상은 플랫폼의 공식 command routing·편집·History·Clipboard 계약과 실제 제품 지침이다. 독립 editor framework의 공개 구현은 이 계약을 실현하는 형태를 비교할 때 사용한다. 라이브러리의 최신 API 모양을 오래된 보편 문법의 증거로 쓰지 않는다.
표준(
standard), 권장 지침(bp), 반복된 관습(de-facto), 아직 수렴하지 않은 제안(frontier)을 구분한다. 댓글에는 읽은 원문이 무엇을 입증하는지와 한계, 작은 비교 사례, 레포와의 연결을 남긴다.이번 회차는 조사와 학습 기록에 집중한다. 기존 PR #726은 설계 초안으로 유지하며 runtime·public API·package 변경과 merge는 진행하지 않는다. 발견한 사항을 후속 구현 이슈로 자동 확대하지 않는다.
developer-1px commentedon Sep 7, 2026
학습 6 — 명령을 보낸 곳, 받을 곳, 실행 가능 여부는 별개의 질문이다
읽은 근거. Cocoa는 명시된 target으로 action을 보내거나, target이 없으면 responder chain에서 수신자를 찾는다. WPF는 command source·target·parameter를 구분하고
CanExecute로 현재 실행 가능 여부를 질의한다. GTK의 action은 이름·enabled 상태·인자 type을 갖고 application/window/widget에 귀속된다. 서로 다른 플랫폼의 공개 계약에서 같은 책임 구별이 반복된다.작은 예제. 문서 A에서 문장을 선택한 뒤 Toolbar의 Copy 버튼을 누른다. 클릭을 받은 곳은 버튼이지만, 복사할 내용은 A가 가진 선택이다. 따라서 “입력 focus 하나가 모든 대상과 상태를 대표한다”는 해석은 부족하다. WPF는 키보드 focus를 잃어도 영역 안의 logical focus를 기억할 수 있는 구조도 설명한다.
레포에 대한 판정. 앞의 초안에서 구별한 Selection·입력 수신자의 방향은 외부 계약에 close하다. 다만 지금의
Scope라는 새 타입 하나로 모두 묶을 근거는 더 약하다. GTK에서 action의target은 인자 값을 뜻하는 문맥도 있어, 다른 플랫폼의 같은 이름을 그대로 대응시키면 오히려 의미가 틀어진다.Cocoa의 menu validation은 수신자를 먼저 찾은 뒤 그 대상의 실행 가능 여부로 메뉴를 활성화한다. “메서드가 있다”, “지금 할 수 있다”, “실제로 성공했다”를 같은 상태로 읽지 않게 한다. 이 사실만으로 모든 플랫폼이 동일한 실패 전파 규칙을 제공한다고 단정할 수는 없다.
근거의 수준. 각 자료는 특정 플랫폼의 공식 API 계약 또는 지침이다. 세 플랫폼에서 역할 구별이 반복되는 것은 안정된 설계 관습의 근거지만, 하나의 범용 command API나 wire format의 표준을 입증하지는 않는다.
읽을거리와 관찰 포인트.
CommandTarget동작은RoutedCommand의 계약이다.다음 질문은 수신자를 결정한 뒤의 거절이 다른 편집기로 넘기는 신호와 어떻게 다른가이다. API 모양을 통일하는 것보다 먼저 검증해야 하는 조합 의미다.
developer-1px commentedon Sep 7, 2026
학습 7 — ‘적용되지 않음’, ‘편집 거절’, ‘이벤트 차단’을 같은 실패로 묶으면 안 된다
명령 후보를 이어서 찾는 동작은 정착한 구현 방식이다. 이미 맡은 편집의 거절을 다른 대상으로 재해석하는 동작과 구별해야 한다. 앞선 초안의 중첩 편집 규칙을 적용할 때 필요한 조건이다.
ProseMirror의 공식 Commands 안내는 적용할 수 없는 명령이 아무 변경 없이
false를 반환하도록 한다.chainCommands는 첫 성공 후보까지 순서대로 시도한다. 기본 Backspace도 선택 삭제 → 뒤쪽 블록 결합 → 앞 노드 선택이라는 후보들을 거친다. 이것은 여러 편집을 모두 수행하는 transaction 묶음이 아니다. 따라서 “Backspace에는 하나의 동작만 있다”, “fallback은 언제나 잘못이다”라는 일반화는 반례를 만난다. ProseMirror Guide — CommandsDOM은 이벤트 전파 중단과 기본 동작 취소를 별개의 flag로 정의한다.
defaultPrevented는 취소 flag를 알려주며, 우리 document commit의 성공 여부를 표현하지 않는다. DOM Standard — Event이를 현재 레포의 계약과 대조하면 세 질문이 드러난다. 아래 표는 새 반환 타입 제안이 아니라 사례를 판별하는 표다.
preventDefault를 호출하지 않음editing.rejected를 확인로컬 읽기: clipboard-rejection.test.ts. 이번 라운드에서는 테스트 내용을 읽어 대조했으며 재실행하거나 중첩 브라우저 동작을 재현하지 않았다.
초안의 후보 규칙은 다음처럼 좁혀 읽는 편이 정확하다.
이것은 모든 플랫폼에서 증명된 보편 규칙이 아니라 현재 설계의 보존 후보다. 특히 ProseMirror의
false는 ‘후보가 적용되지 않는다’는 의미이며 우리EditingResult.ok: false와 자동으로 대응하지 않는다. 두 boolean을 기계적으로 연결하면 위 표의 구별을 잃는다.근거 강도: DOM 이벤트 구별은 해당 플랫폼의
standard; ProseMirror 연결은 해당 구현의 공개 계약이며 인접 비교 대상이다. 중첩 편집의 거절 이후 경로에 대한 생태계 전체 합의는 아직absent로 둔다. 이 레포가 선택할 안전한 계약과 외부에서 이미 정착한 규칙을 구별한다.읽으면서 확인할 질문: 셀 내부의 텍스트 삭제가 거절되었을 때, 셀 전체를 지우는 것은 같은 명령의 다음 후보인가, 수신 대상이 달라지는 새 명령인가? 코드 설계 전에 이 경계가 사례로 답해져야 한다.
developer-1px commentedon Sep 7, 2026
학습 8 — Undo의 공통 문법은 오래됐지만, History의 범위는 하나로 굳지 않았다
후속 정리: 사용자와 확인한 방향은 편집 Undo 시 선택을 함께 복원하는 기본 Profile을 제공한다는 것이다. 아래의 다양한 History 정책은 그 기본값의 적용 범위와 변형을 설명한다. 사용자 전제 정리, 기본값을 뒷받침하는 구현 근거
Undo를 제공한다는 약속과 ‘어떤 기록을 한 번 되돌리는가’라는 약속을 분리해야 한다. 입력 focus, 기록의 소유자, 기록에 포함할 변경, 한 step의 묶음은 서로 다른 결정이다.
trackedOrigins, 시간 기반 묶음과stopCapturing()을 구별AppKit 문서는 2011년의 공식 아카이브다. 당시의 설계 근거로 읽으며 현재 모든 macOS 앱의 동작이라고 주장하지 않는다. Qt는 독립적인 현재 native framework 계약이다. Yjs는 협업 구현이라는 인접 비교 대상이며 이것만으로 협업 Undo의 유일한 표준을 입증하지 않는다.
기존 초안에서 한 가지 설명은 더 좁혀야 한다. ‘일시적 selection이므로 Undo 대상이 아니다’도 보편 명제가 아니다. AppKit은 document 상태에 포함하지 않는 view selection도 사용자 편의를 위해 Undo에 등록할 수 있다고 설명한다. 이는 앞서 본 GIMP의 mask 제작보다 직접적인 반례다. ‘저장되는 상태인가?’와 ‘Undo로 되돌릴 상태인가?’는 별개 축이다. 같은 AppKit 문서의 Undo and the Control and View Layers
현재 레포와의 거리:
EditingHistory를 교체 가능한 owner로 둔 방향은 위 사례들과 close하다. history.tsselection-only는 문서 History entry를 만들지 않으며, 외부 document 변경은 local inverse History를 비운다. 이는 명시된 구현 정책이다. 모든 편집기의 역사적 공통 규칙으로 승격할 근거는 없다. session-history.test.ts판정: ‘명령과 History 수신처를 구별한다’는 설계 경향은
stable; 모든 문서·view·selection에 적용할 단일 History 범위는absent다. 기존 EG-SELECT·EG-HISTORY는 현재 profile의 계약으로 보존하되, 다른 profile의 적합성을 판정할 때 이 정책을 보편 전제로 쓰지 않아야 한다.읽을 때의 사고 실험: 같은 문서에서 A는 문장을 쓰고 B는 객체를 옮겼다. A로 돌아와 Undo하면 ‘B의 마지막 변경’, ‘A의 마지막 변경’, ‘A의 현재 입력 draft’ 중 무엇을 되돌리는가? 정답을 먼저 하나 고르는 대신 각 동작에 필요한 History 귀속 계약을 적어 보면 하이라키가 드러난다.
developer-1px commentedon Sep 7, 2026
학습 9 — Copy/Paste의 공통점은 ‘하나의 만능 payload’보다 ‘표현을 사이에 둔 교환’에 있다
서로 다른 편집기가 각자의 document model을 유지하면서도 내용을 교환한다. 이 경계가 오래된 플랫폼 자료에서 반복된다.
Windows는 같은 내용을 여러 clipboard format으로 제공하고 수신자가 이해하는 표현을 선택하는 방식을 설명한다. Apple의 pasteboard 아카이브도 하나의 item을 RTFD·RTF·plain text처럼 여러 표현으로 제공해 서로 다른 앱의 능력을 연결한다. Qt의
QMimeData.formats()역시 표현과 우선순위를 노출한다. API 모양은 다르지만 교환 내용과 표현을 구별하는 방향은stable로 볼 근거가 있다. Windows Clipboard Formats, Apple Pasteboard, Qt QMimeData위 트리는 설명용이다. 모든 editor에 HTML이나 특정 JSON schema를 강제하는 제안이 아니다. 여러 item과 한 item의 여러 표현도 같은 개념이 아니다.
여기에 중요한 반례가 있다. 가장 풍부한 표현을 읽었다고 사용자가 원하는 Paste 의미까지 결정되는 것은 아니다. Word는 같은 문서/다른 문서/다른 앱에서의 붙여넣기 설정을 구별하고, 원본 서식 유지·서식 병합·텍스트 전용을 제공한다. 즉, 표현을 읽을 수 있는 능력과 어떤 변환을 원하는지라는 정책은 다르다. Word — Control the formatting when you paste text
현재 레포에서는 이 구별의 일부가 이미 보인다.
로컬 읽기: Rich Text 표현, Web 표현 선택 테스트, Web binding.
비교 판정: 여러 표현과 editor별 수신 해석을 둔 현재 방향은
close; 하나의 공통 wire schema로 모든 편집 장르를 통일한다는 근거는absent다. 같은 format 이름만으로 내용 의미까지 호환된다고 인증해서도 안 된다.읽을 때의 질문: 굵은 글씨가 있는 표를 문자열 입력창에 붙여넣으면 무엇을 보존해야 하는가? ‘문자열만 받는 대상’과 ‘표를 지원하지만 지금은 읽기 전용인 대상’에서 fallback을 같은 이유로 실행해도 되는가? 이 구별이 학습 7의 ‘후보 탐색과 거절’에 연결된다.
developer-1px commentedon Sep 7, 2026
학습 10 — 사용자 전제 보정: 유연한 기반 위에, 정착한 default를 Profile의 계약으로 제공한다
조사 중 사용자가 의도를 더 명확히 했다. Core는 여러 정책을 수용할 수 있게 유지하고, 사람들이 이미 익숙한 편집 동작은 기본 Profile로 제공한다.
Cmd+Z → Undo, 편집 Undo 시 선택 영역의 복원이 대표 예다.이 전제를 이후 판단의 기준으로 삼는다. 학습 7–9의 반례는 기본값을 포기할 이유가 아니라, 기본 Profile의 적용 범위와 변형을 가르는 근거다. 예외가 존재한다는 사실만으로 널리 정착한 기본 동작을 계속 미결정 상태에 두지 않는다.
이는 설명상의 구분이며 새 package나 중앙 profile registry를 만들자는 제안이 아니다. 기존의 대상별 계약과 입력별 계약을 조합해 Hands profile로 검증하는 구조 안에서 구체화할 수 있다.
특히 Undo에 대해 두 가지를 분리한다.
Cmd+Z는 무엇을 뜻하는가?‘선택 영역도 Undo에 포함’은 우선 편집과 함께 선택을 복원한다는 뜻으로 이해했다. 선택 이동을 독립 Undo step으로 기록하자는 요구로 확대 해석하지 않는다.
기본 Profile을 쓰는 사용자에게는 이것이 실제로 믿을 수 있는 약속이어야 한다. 따라서 이후 기본 동작을 바꿀 때도 호환성을 검토해야 한다. 확장이 가능하다는 이유로 같은 Profile 이름 아래 관찰 가능한 동작을 임의로 바꾸면 안정화 목표를 잃는다. 다만 어느 옵션을 Profile 안에서 허용하고 어느 차이를 다른 Profile로 식별할지는 구체적 사례로 정할 사항이다.
이후 조사 질문도 ‘모든 앱이 반드시 똑같은가?’에 머무르지 않고, **‘어떤 동작을 기본으로 제공할 근거가 충분하며, 어떤 차이를 명시해야 사용자의 예상이 보존되는가?’**로 좁힌다.
이번 댓글은 사용자의 설계 전제를 기록한 것이다. 런타임·공개 API·기존 PR은 변경하지 않았다.
developer-1px commentedon Sep 7, 2026
학습 11 — 기본 Profile로 채택할 근거와, 더 명시해야 할 조건
Cmd+Z → Undo와 편집 전 선택 복원은 기본 계약으로 구체화할 근거가 있다. 예외 조사에 이어 기본값을 뒷받침하는 실제 editor 계약을 읽었다.CKEditor는 Undo batch와 함께 편집 전 selection을 기록하며, Undo 명령이 selection을 복원한다고 명시한다. 여러 primitive operation을 한 Undo step으로 묶는 설명도 제공한다. CKEditor Undo, UndoCommand
CodeMirror는 기본 history keymap에서
Mod-z를 일반 Undo에,Mod-u를 selection 변경도 대상으로 하는undoSelection에 연결한다. 이는 ‘내용 편집의 Undo’와 ‘선택 변경의 Undo’를 별도 능력으로 제공하는 참고 사례다. CodeMirror — Undo HistoryCKEditor의 사용 안내도 Windows 계열
Ctrl+Z와 macOSCmd+Z를 Undo의 익숙한 입력으로 설명한다. 두 editor를 전체 편집 장르의 유일한 표준으로 삼지는 않지만, 사용자가 제시한 default를 뒷받침하는 독립 구현의 신호로 볼 수 있다. CKEditor — Undo/RedoCmd+Z, Windows 기본Ctrl+Z→ Undo 의도마지막 행은 APG Grid의 Editing and Navigating Inside a Cell을 읽은 결과다. APG는 여러 관습을 허용하는
bp자료다. 그중 하나를 기본 Profile로 고를 수 있으며, 그 선택을 모든 셀 입력기의 유일한 법칙이라고 설명할 필요는 없다.현재 레포는 이미 내용과 before/after selection을 함께 복원하는 테스트를 가지고 있다. session-history.test.ts. 따라서 이 기본 계약은 처음부터 새로 발명해야 하는 상태가 아니다. 아직 빈 곳은 이 의미를 입력·중첩·여러 view 조합에서도 같은 계약으로 검증하는 부분이다.
하이라키에서 Profile은 선택한 규칙과 적합성 기준을 묶는다. 구현 책임은 기존 canonical owner에 남는다.
이 기본값을 제공하기 위해 저수준
JSONDocumentCore에 키보드나 모든 History 정책을 넣을 필요는 없다. 작은 기반과 정착한 기본 동작을 함께 유지할 수 있다.학습용 확인 사례:
Alpha의ph선택 →X로 교체 → Undo →Alpha와ph선택 복원 → Redo → 교체 후 내용·선택 복원. 이 사례를 어느 공개 API 조합으로 실행하고 관찰할 수 있는지가 Profile의 구체적인 약속이 된다. 이 전체 입력 시나리오는 이번 라운드에서 실행한 테스트가 아니라, 기존 근거를 바탕으로 적은 적합성 후보다.developer-1px commentedon Sep 7, 2026
학습 12 — 기본 Cut 계약을 검증할 때는 callback 뒤의 native 동작도 관찰해야 한다
‘payload 확보가 실패하면 원본을 제거하지 않는다’는 기본 계약을 제공하되, 검증 범위를 editor callback 밖까지 잡아야 한다. 이것은 기본값을 미루는 이유가 아니라 그 약속을 실제 환경에서 입증할 조건이다.
현재
createWebClipboardBinding.cut()은 다음 순서다.읽은 코드상 쓰기 실패 분기는 이 binding 안에서
preventDefault()를 호출하지 않는다. 기존 테스트는 쓰기 실패 시 editor의 제거 callback이 호출되지 않고 document/selection/history가 그대로임을 확인한다. Clipboard는 메모리 객체로 대체되어 있다. Web binding, clipboard-rejection.test.tsW3C Clipboard API 초안은 취소하지 않은 cut에 대해 editable selection의 복사·제거라는 기본 동작을 설명한다. 반대로 cut을 취소하면 custom clipboard data를 사용하며 제거는 handler가 맡는다. 따라서 우리 callback의 미호출만으로 브라우저 전체에서 원본 제거가 없다고 결론 내릴 수 없다. 또한 이벤트의
DataTransfer에 표현을 썼다는 관찰과 실제 OS clipboard 반영 완료는 같은 관찰 시점이 아니다. Clipboard API and events — 6.2, 8.2이 자료는 2026-06-24 Working Draft다. 해당 이벤트 모델을 읽은 근거로 사용하며 모든 브라우저·OS에서 실패 상황을 직접 재현했다는 뜻은 아니다.
특히 Rich Text binding에는 cut listener 외에
beforeinput(deleteByCut)처리도 있다. 그러므로 후속 경로까지 포함한 판정이 필요하다. contenteditable.ts이번 발견은 재현 전 검증 공백으로 기록한다. 특정 브라우저에서 실제 데이터 손실을 확인한 확정 버그로 등록하지 않는다. 해결 방향을 곧바로 ‘더 일찍 모든 이벤트 취소’로 결정하지도 않는다. 입력을 맡은 실패와 명시적 native 위임의 경계를 먼저 적용해야 하기 때문이다.
현재 초안의 ‘OS clipboard와 document 사이의 분산 transaction을 약속하지 않는다’는 한계는 유지된다. 그 안에서도 원본 제거 조건과 실패 결과는 기본 Profile이 명확히 보장할 수 있다.
developer-1px commentedon Sep 7, 2026
학습 13 — 기본 편집 의미를 고정하려면, IME 이벤트 하나를 commit 하나로 보지 않아야 한다
‘조합해 입력한 내용을 Undo로 되돌린다’는 사용자 약속은 Profile로 정하고, native 입력 중간 상태를 정리하는 책임은 입력 계층이 맡는다.
Input Events Level 2의 2026-05-01 Working Draft는 IME 조합 과정의
insertCompositionText를 취소 불가능한 beforeinput으로 정의한다. 조합 중 DOM의 active text passage가 갱신되는 과정도 설명한다. 따라서 모든 입력을 ‘DOM이 바뀌기 전에 앱이 허가하고 곧바로 commit’하는 한 단계로 표현하면 이 모델을 담기 어렵다. Input Events Level 2 — 6.1.2, 7이 구별이 있으면 ‘실패한 편집은 자신의 partial document mutation을 남기지 않는다’는 계약과 입력 중 임시 표시를 함께 설명할 수 있다. native 표시가 잠시 달랐다는 사실만으로 확정된 JSON document가 이미 변경됐다고 보지 않는다. 반대로 입력 계층은 확정·거절·취소 이후 표시와 model을 다시 맞출 책임이 있다.
현재 레포에는
ㅎ → 하 → 한으로 DOM을 변화시킨 뒤 한 번의 Undo로 원래 내용이 돌아오는 사례와, 조합이 원래 DOM으로 돌아왔을 때 새 Undo 기록이 생기지 않는 사례가 있다. 이는 합성 이벤트와 DOM fixture를 사용하는 테스트이며 실제 OS IME 세션 검증과 구별한다. Rich Text composition 테스트자료를 읽는 방법에서도 유용한 사례가 나왔다. 다음 두 발행 초안은 compositionupdate와 beforeinput의 순서를 다르게 서술한다.
이 차이만 보고 ‘현재 브라우저가 서로 합의하지 못했다’고 결론 내리면 안 된다. w3c/uievents #354의 본문뿐 아니라 마지막 댓글까지 읽으면, 2023-12-08에 Chromium 변경의 web compatibility를 확인했고 spec 갱신을 요청했다는 기록이 나온다. 현재 열린 이슈라는 표시와 실제 구현 수렴 상태는 별개일 수 있다. 마지막 확인 댓글
판정: 진행 중 입력·확정된 편집·History 작업 단위를 구별하는 현재 방향은 외부 모델과
close하다. 이 자료만으로 2026년 모든 브라우저/OS/IME의 실행 순서를 인증할 수는 없다. 안정화할 기본 의미를 정한 뒤 실제 환경별 입력 trace가 그 의미로 귀결되는지 검증하는 순서가 적절하다.다음 검증 후보는 범위가 작다: 조합 완료 후 Undo, 조합 취소, 조합 중 Undo 입력, 조합 중 focus 이동. 각 경우에 내용·선택·History·입력 상태가 어떻게 끝나야 하는지를 먼저 적는다. 이것은 브라우저의 특정 지연 시간 상수를 Core 계약으로 올리자는 제안이 아니다.
developer-1px commentedon Sep 7, 2026
추가 조사 결과와 읽기 순서 — 기본 Profile을 제공한다는 전제로 정리
작은 기반 계약을 유지하면서, 정착한 편집 문법을 기본 Profile의 구체적 약속으로 제공할 수 있다. 이번 조사에서 가장 중요한 보정은 예외를 찾는 작업과 기본값을 결정하는 작업을 함께 해야 한다는 점이다.
사용자가 도중에 명확히 한 전제를 우선해 읽는다:
Cmd+Z → Undo, 편집과 함께 선택 영역 복원은 기본으로 제공한다. 다양한 구현의 반례는 그 기본값의 범위와 변형을 설명한다.하이라키에 대한 결론
현재 문서의 대상별 계약 + 입력 계약 → 함께 검증하는 Hands profile이라는 구분을 유지할 근거가 충분하다. Profile이 약속을 묶고, 동작 구현은 Selection·Editing·History·Affordance·Web의 정본 owner가 맡는다. 저수준 Core의 필수 API를 늘리는 결론은 나오지 않았다.
기존 문서도 이 방향을 담고 있다. Official Hands Profile은 schema·selection·intent·clipboard·history·affordance의 조합을 설명한다. Rich Text v1 profile은 이미 편집 전후 selection과 composition History의 요구사항을 둔다. 기존 계약을 기본 Profile이라는 사용자 관점에서 연결하고 검증하는 설계를 진행할 수 있는 단계다.
더 좁혀 검증할 것
다음 작업의 중심은 앱 종류를 끝없이 추가하는 조사보다, 기본 Profile이 약속할 결과를 적고 아래 조합에서 입증하는 데 둘 수 있다.
편집 Undo 시 선택을 복원하는 기본 계약과, 선택 이동 자체를 독립 Undo step으로 기록하는 정책은 계속 구별한다. 기본 Profile에서 허용할 설정과 다른 Profile로 식별할 차이도 사례별로 명시해야 한다.
이번 라운드의 결과 범위
학습 댓글 8개에 공식 자료·로컬 근거·반례·읽을 질문을 연결했다. 연결한 외부 URL 22개를 열어 확인했고, 잘못된 APG 절 anchor 1개를 실제 anchor로 바로잡았다. 본문 안의 고정 commit 소스 링크 9개도 파일과 줄 위치를 확인했다. 링크 검사는 자료 접근성과 위치 확인이며 외부 구현의 적합성 인증은 아니다.
런타임·공개 API·테스트·package·설계 파일은 변경하지 않았다. #726은
c8570dc7그대로 열려 있으며 머지하지 않았다. 기존 테스트는 내용을 읽어 대조했고, 이번 라운드에 테스트 재실행이나 실제 브라우저/OS IME 검증은 수행하지 않았다. 이슈는 후속 설계와 검증을 위해 열어 둔다.developer-1px commentedon Sep 7, 2026
기본 Profile 설계 반영 — 조사 결과를 기존 초안과 PR에 연결
사용자가 “Core는 유연하게 다 가능하게 가져가되 default를 제공”, “Cmd+Z가 Undo”, “선택했던 영역도 Undo에 포함”이라는 전제를 확인하고 이어서 “계속해”라고 요청했다. 학습 10의 전제를 기존 설계 초안에 반영한다.
Goal Anchor — 원래 범위 유지
이번 구체화는 다음 의미를 보존한다.
현재 #725와 #726이 이 설계 작업을 소유하고 있다. 원래 작업 디렉터리의 변경은 보존하고 기존 작업 브랜치
issue-725-editing-grammar-derivation에서 진행한다. 문서 검사는docs:evaluate, Markdown 링크/렌더링, 기존 EG 규칙·owner 보존과 범위 대조로 한다. 추가 API나 실제 입력 동작의 구현·머지는 이번 작업에 포함하지 않는다.developer-1px commentedon Sep 7, 2026
학습 14 — 단축키에서 근육기억으로 정착한 편집 문법을 찾기
사용자가 조사 기준을 보완했다. “단축키가 만들어진다는 것은 변하지 않을 중요한 관습”, “근육기억 때문에 한번 정하면 되돌리기 어렵다”, 따라서 핵심 기능을 찾을 때 “단축키를 제공하는 기능부터” 살펴보자는 힌트다. 이를 기존 #725의 공통 문법을 도출하는 방법에 반영한다. 원래 Goal Anchor와 문서 변경 범위는 유지한다.
채택하는 조사 방법
단축키는 반복해서 실행하도록 제품이 드러낸 기능을 찾는 출발점이다. 특히 여러 제품과 오랜 자료에서 반복되는 기능부터 대상·결과·선택·복원을 비교한다. 단축키가 있다는 사실만으로 모든 기능을 Core로 승격시키거나 영구 표준으로 인증하지 않는다.
이 도식은 조사 결과를 분류하는 방법이다. 새로운 command bus나 runtime 계층 설계가 아니다.
공식 자료로 비교해 볼 예
Cmd+Z, Excel의Ctrl+ZShift+ArrowF2·Escape현재 제품 문서는 현재 공개 동작의 근거다. 같은 의미가 얼마나 오래 유지됐는지는 기존에 읽은 1992년 HIG·Windows Edit 메뉴 지침 등과 대조해야 한다. 현재 단축키 표만으로 30년의 연속성을 증명했다고 표시하지 않는다.
기본값 호환성에 주는 의미
설계 판단은 근육기억으로 익힌 조작도 호환성의 대상이라는 것이다. 기본
Cmd+Z를 유지하더라도 다른 History에 전달하거나 편집 전 선택을 복원하지 않게 바꾸면 사용자가 익힌 작업은 달라진다. 반대로 사용자가 Profile이 허용한 설정으로 키를 바꾸는 것은 기본값을 몰래 바꾸는 일과 구별한다.따라서
설정 생략 + 편집 맥락 + 입력 → 대상·결과·후속 선택·History를 함께 검증하도록 문서의 기본 Profile 절에 연결한다. 단축키에 직접 드러나지 않는 선택 mapping·원자성·gesture 취소도 발견된 작업이 성립하는 데 필요하면 기반 계약에 남는다.현재 변경은
standards/editing-grammar.md의 조사 방법과 기본값 계약을 보완한다. runtime·공개 API·Stable profile을 변경하거나 아직 실행하지 않은 입력 사례를 통과로 표시하지 않는다.developer-1px commentedon Sep 8, 2026
학습 15 — 유연한 기반 위에서 기본 Profile의 약속을 구체화한 결과
PR #726을 갱신했다. 커밋
412f5121은standards/editing-grammar.md하나만 변경한다. 기존 EG 규칙 9개와 canonical owner 표는main대비 그대로 유지했다.이제 문서에서 결정한 것
여기서 유연성은 가능한 정책을 지원하는 능력이고, 기본값은 그중 무엇을 실제로 약속하는가의 결정이다. 기반 API가 여러 동작을 표현할 수 있어도 같은 Profile의 기본 동작을 임의로 바꿔도 된다는 결론은 나오지 않는다. 사용자의 설정 생략도 유효한 사용이므로 호환성 검증에 포함한다.
사용자가 추가한 단축키 힌트도 같은 결론으로 연결했다. 기본 키를 유지하더라도 수신 History나 선택 복원을 바꾸면 근육기억으로 익힌 작업이 달라진다. 학습 14에 단축키에서 문법 후보를 추출하는 방법과 공식 읽을 거리를 따로 남겼다.
Undo의 약속을 검토 가능한 사례로 바꾸기
Rich Text의 한 text node에서
Alpha의ph를 선택하고X로 바꾼다고 하자. 외부 변경은 없고 시작 History는 비어 있다.Alphaph선택AlXaAlphaAlXaUndo 다음에 선택만 옮기는 경우도 별도로 적었다. 기본 Profile에서는 그 이동이 새 문서 History entry를 만들거나 Redo를 지우지 않으며, Redo는 기록된 편집 후 선택을 복원해야 한다. 이는 편집과 함께 선택을 복원하는 정책과 선택 이동 자체를 Undo 기록에 넣는 정책을 구별한다.
이 표는 새로 구체화한 기대 결과이며 새 테스트 통과를 주장하지 않는다. 기존 model selection 증거와 실제 native range 복원 증거도 분리했다. API·binding을 바꿀 필요가 있는지는 기존 Web·Affordance·Editing·domain API로 이 사례를 연결할 때 확인하도록 설계 위치를 남겼다.
검증과 남은 경계
412f5121의 CI: Plan·Package·Site 통과, External kit은 계획에 따라 skippednpm run docs:evaluate,git diff --check통과.원래 작업 디렉터리의 변경은 보존했다. 작업 브랜치는
issue-725-editing-grammar-derivation이며 PR은 열린 상태다. UI 변경이 없어show-me는 해당하지 않는다.developer-1px commentedon Sep 8, 2026
기본 동작별 계약표와 최소 코드 변경안 — 실행 계획
사용자가 다음 단계를 물었고, 다음 산출물을 “기존 설계 문서 안의 기본 동작별 계약표와, 그 계약을 만족시키기 위한 최소 코드 변경안”으로 제안한 뒤 “해보자”라고 승인했다. 기존 #725 / #726에서 이 설계를 구체화한다.
Goal Anchor — 기존 설계 목표 유지
대상 → 결과 → 후속 선택 → Undo 단위로 비교하고, 공통 보장·대상별 의미·입력 해석·기본 Profile의 약속을 기존 owner에 연결한다.선택 → 교체 → Undo → Redo를 기존 공개 API로 확인해, 코드 변경이 필요한 지점과 검증만 필요한 지점을 구별한 변경안을 문서 PR로 제공한다.보존할 합의
검증은 기존 관련 테스트와 필요한 공개 API 실행 확인,
docs:evaluate, Markdown 링크·렌더링, EG 규칙·owner 보존으로 한다. 임시 실행 확인과 영구 conformance vector, native browser/OS 입력의 증거를 구별해 남긴다. 원래 작업 디렉터리의 변경을 보존하고 기존issue-725-editing-grammar-derivation브랜치를 사용한다.developer-1px commentedon Sep 8, 2026
학습 16 — 계약표를 공개 API에 대입해 보니 Core보다 조합 경계가 남았다
선택 → 교체 → Undo → Redo부터 실제 공개 API로 확인했다. 저장소의 현재 source를 빌드한 뒤 package entrypoint를 사용했으며 runtime 코드는 수정하지 않았다.확인된 동작
Alpha의ph를X로 교체하면AlXa와 offset 3의 caret이 된다.Alpha와 편집 전 선택 범위·방향을 복원한다.AlXa와 편집 후 caret을 복원한다.키 입력 확인은
createWebKeyboardAdapter().resolve가 만든 의도를 editor의 공개undo·redo에 전달한 범위다. DOM 수신·OS IME·native selection 복원까지 통과했다고 해석하지 않는다. 이번 임시 실행을 영구 conformance suite의 테스트 개수에 더하지도 않는다.이 증거 때문에 해당 경로에는 Core나 History API의 확장이 필요하다고 제안하지 않는다. 다음 구현에서는 같은 사례를 기존 owner의 conformance binding에 정착시키고 실제 입력 경로와 연결하면 된다.
기본 계약과 현재 API 사이의 공백
selectAllAffordance(..., { allSelected: true })는clear반환createRenameSession은 draft를 지우고onFinish호출voidcallback은 별도 호환 경로로 보존마지막 행은 source 비교다. 예를 들어 Web 기본 resolver는
Alt+Mod+Z를 해석하지 않지만 Rich Text Web의 현재 Undo 조건은altKey를 검사하지 않는다. 공통 resolver로 연결할 때 기존 수용 범위를 몰래 바꾸지 않도록 입력 정책·호환성 사례를 먼저 명시해야 한다.여기서 draft 유지와 반복 전체 선택 유지는 이 초안에서 채택한 기본 Profile의 결정이다. 기존 API가 이미 약속한 규칙을 위반했다는 판정과 구별한다. 특히 rename의 현재 callback은
void계약이어서, 반환한 편집 결과를 해석하리라고 기대할 근거가 없다.하이라키에 대한 결론
Order Demo는 정본 rename session과
item.rename을 연결하고, Canvas Demo는 정본 select-all affordance와 Object의selection.set을 연결한다. 기본 정책이나 거절 복구를 이 Host들에 추가하면 같은 책임이 다시 흩어진다. 현재 owner의 계약을 보완하는 변경안으로 남겼다.현재 관련 기존 테스트는 10 files / 166 tests 통과했다. 대상은 기존 공통 grammar binding, select-all 의미, session History, Tree·Object·Sheet editor, Affordance와 Web adapter다. 계약표와 변경안은
standards/editing-grammar.md에 반영 중이며 구현 변경은 이 문서 PR의 범위 밖이다.공개 API 실행 재현 코드와 실행 조건
저장소 루트에서 Node 24와 해당 checkout의 dependencies를 사용했다. 먼저 다음 명령으로 현재 source의 빌드 결과를 만들었다.
npm exec tsc -- -b packages/json-document-rich-text packages/json-document-affordance아래 코드를 파일에 저장한 뒤 저장소 루트에서
node --input-type=module < 저장한파일.mjs로 실행한다. 공개 package entrypoint를 해석하도록 루트를 실행 위치로 둔다.다음 코드는 제안한 기본 계약의 통과 테스트가 아니라 현재 정책과 거절 결과를 재현하는 코드다.
label.rejected는 검증 실패를 만들기 위한 fixture 규칙이다.기존 테스트 실행:
developer-1px commentedon Sep 8, 2026
기본 계약표·최소 코드 변경안 완료
PR #726의 커밋
97405f78에 반영했다.standards/editing-grammar.md안에서 기존 표를 확장·정리했으며 변경 파일은 하나다.산출물
repeat·tryCommit호출 초안, 기존 호출의 호환성, 완료 판정 사례와 구현 순서를 남겼다. 이 초안을 runtime에 적용하지는 않았다.확인한 증거
97405f78의 CI: Plan·Package·Site 통과, External kit은 계획에 따라 skipped관련 기존 테스트 10 files / 166 tests, 현재 source의 관련 package 빌드,
docs:evaluate,git diff --check가 통과했다. 별도로 실행한 12개 공개 API 사례는 model·기본 keymap 범위에서 통과했다. 현재 토글 정책과 거절 후 draft 종료는 공백을 확인한 결과이며 제안한 기본 계약의 통과가 아니다. 재현 코드와 해석은 학습 16에 보관했다.내부 링크 46개 참조 / 38개 대상, GFM 표 16개의 열 구조·code block 6개·중복 없는 anchor를 확인했다. 기존 EG 규칙 9개와 canonical owner 표는
main대비 보존했다. 원격 PR 본문·문서·커밋과 #725의 원래 범위 및 승인된 실행 계획을 대조했다.작업 브랜치는
issue-725-editing-grammar-derivation, 작업 checkout은 clean이며 원래 디렉터리의 변경은 보존했다. PR은 열린 상태이고 UI 변경이 없어show-me는 해당하지 않는다. Native 입력·중첩·여러 view의 History와 새 기본 정책의 영구 conformance 증거는 후속 구현 단계의 검증 항목으로 남긴다.developer-1px commentedon Sep 8, 2026
승인된 후속 구현으로 연결
사용자가 기본 계약표와 최소 코드 변경안을 전달받고 “진행해”라고 요청했다. 네 구현과 영구 회귀 검증은 #727에서 진행한다. #725와 #726의 문서 설계 범위는 유지하며 기존 원문·판단 기록을 변경하지 않는다. 구현은 최신
main기반의 별도 PR로 제공한다.developer-1px commentedon Sep 8, 2026
프로토콜 건강도 감사 — 책임의 중복, 행동 범위, 최소성
판정: Core의 여섯 멤버는 책임이 비교적 선명하다. 그러나 전체 편집 프로토콜을 ‘필요한 행동을 모두 제공하며, MECE하고 최소화되었다’고 판정할 수는 없다. 같은 책임의 재구현이 있고, 일부는 실제 동작 불일치로 이어진다.
이번에는 코드를 수정하지 않았다. 아래는 설계 판단과 후속 수정의 근거다.
감사 기준과 범위
ba1f0ee. 감사 시점에 #730은 OPEN이다. main에 모두 반영된 상태라는 뜻이 아니다.standards/editing-grammar.md. 설계 초안과 실행 증거를 분리했다.현재 공통화의 실제 범위
cutEditingClipboard사용editingGrammar(...)suiteCore의
JSONDocument는value / at / query / validatePatch / commit / subscribe로 구성된다. 현재 조사에서 이 여섯 책임 중 하나를 없애야 한다는 근거는 찾지 못했다. 단일 주소 읽기와 질의, 변경 검증과 실행, 현재 값과 변경 관찰은 서로 다른 요청이다. 다만 멤버가 여섯 개라는 사실 자체가 내부 구현의 중복 부재를 보장하지는 않는다.1. 주소 해석을 재구현하여, 같은 editor를 다른 소비자가 읽지 못한다 — 우선 수정
정본은 Core의 Pointer 모듈이다.
Rich Text editor는
document.at(pointer)를 사용한다. 반면 React의documentAtPointer는slice/split/replaceAll로 주소를 직접 해석한다.공개
createRichTextEditor와RichTextEditorSurface, ReactrenderToString으로 재현했다./editor#/editorRich Text document was not found at "#/editor".DOM이나 로그인 상태가 필요한 재현이 아니다. editor가 받아들인 주소를 그 editor의 공식 React 소비자가 받아들이지 못한다.
또한 토큰 인코딩은 canonical 구현 외에 다음 세 곳에서 같은
~0 / ~1규칙을 구현한다.escapeSegissuePathToPointerrecordPointer분류: 중복 구현. 인코딩은 이미 있는
buildPointer를 소비할 수 있다. React의 snapshot 읽기는 canonical 주소 해석을 사용하면서 snapshot의 참조 동일성과 성능을 보존하는 연결 방법을 정해야 한다. Core port의 멤버를 늘리는 것이 자동으로 필요한 것은 아니다.완료 조건: 동일한 지원 주소 집합에 대해 Core → Rich Text → React가 같은 대상을 읽고, token 인코딩의 독립 구현이 남지 않는다.
2. ‘JSON 값으로 유효하다’의 정의가 계층마다 다르다 — 우선 수정
정본 Core의 JSON 검증·복제는 유한한 숫자, 배열의 실제 원소, 허용 객체 형태 등을 검사한다.
Editing의
isClipboardJSONValue는 이 책임을 별도로 구현한다. Sheet·Database clipboard parser가 함께 사용한다. Rich TextisJSONValue에도 일반 JSON 값 판별이 따로 있다.공개 API 실행 결과:
applyPatchNaNnot_serializableInfinitynot_serializablenew Date(0)not_serializableArray(1)not_serializable이는
parse(unknown)에 객체를 직접 전달한 결과다. JSON 문자열을 통해 NaN이 전달된다는 주장이나 실제 문서가 손상되었다는 주장은 아니다. 경계의 판정 자체가 일치하지 않는다는 증거다.분류: 중복 구현 + canonical API 공백. 공통 JSON 유효성은 한 owner가 제공하고, Sheet의 직사각형 조건이나 Rich Text schema처럼 도메인별 추가 제약은 각 owner가 유지해야 한다. 단순히 모든
clone함수를 지우자는 결론은 아니다. 복제·직렬화·검증은 서로 다른 책임일 수 있다.완료 조건: 도메인 parser가 JSON 값으로 수용한 결과를 Core가 같은 이유로 거절하지 않는다. 도메인 제약과 JSON 자체의 제약을 따로 검증한다.
3. 기본 단축키의 의미가 Profile보다 사용한 함수에 좌우된다 — 우선 수정
정본 후보인 Web keyboard adapter는 modifier를 포함해 chord를 해석한다.
하지만 Composer는
commandKey + z를 따로 해석한다. Composer React는 이 입력을 만들면서 Alt 정보를 전달하지 않는다. Affordance의 Delete·Select All helper와 Annotation Host에도 개별 key 해석이 있다.Ctrl+Alt+Zhistory.undoCtrl+BackspacedeleteAffordance:deleteCtrl+Alt+Shift+AselectAllAffordance:select-all마지막 행은 Web 기본 keymap이 Select All 자체를 제공하지 않는다는 차이도 포함한다. 모든 helper가 같은 입력 집합을 지원해야 한다는 주장은 아니다. 특히 텍스트의 단어 삭제와 객체 삭제는 다른 의미일 수 있다.
분류: 중복 입력 해석 + 기본 정책의 소유권 공백. 차이가 필요하면 Profile에서 선택해야 한다. helper를 달리 썼다는 이유만으로 modifier가 누락되거나 기존 단축키 의미가 달라지면 장기간 호환성을 지키기 어렵다.
완료 조건: raw key → semantic command의 기본 해석을 공통으로 소비하고, Composer의 제출/줄바꿈 같은 추가 정책은 유지한다. modifier, 중첩 편집 맥락, 실제 소비자의 연결까지 검증한다.
4. Annotation은 Selection과 도메인 연산을 우회한다
Annotation editor는 선택 ID 추가·제거, toggle, primary 복구를 직접 구현한다. 정본 KeySelectionFamily가 이미 같은 책임을 제공한다.
분류: 중복 구현. 다만 선택 순서와 primary 결정 규칙은 현재 구현의 관찰 가능한 정책이므로 단순 교체하면 안 된다. 정본이 그 정책을 지원하는지 확인하고 연결해야 한다.
또한 Host의
projectGestureAnnotation은 editor의 move/resize 계산을 다시 구현한다. 코드상 화살표 끝점이 시작점에 겹치면 editor는 resize를 거절하지만 Host preview는 그 형태를 만든다. 이 부분은 소스 대조 결과이며 실제 포인터 조작으로 재현하지 않았다.분류: canonical API 공백. 도메인 owner가 preview와 commit에 쓸 동일한 연산 결과를 제공하지 않아 Host가 재구현한다.
완료 조건: Selection의 공통 family를 소비하고, preview와 commit이 같은 도메인 규칙을 사용한다. Host는 gesture의 현재 입력과 표시를 연결한다.
5. 드래그 수명주기에 상태 소유자가 겹친다 — 통합 설계 후보
createGestureSession: 공통 begin/preview/commit/cancel.createBoardDragSession: item/target 규칙과 별도 active 상태.createWebDragDropSession: DOM 입력을 받지 않으면서 별도 active item과 같은 수명주기를 소유.분류: Web session의 책임 배치 문제, Board의 공통 수명주기 중복 후보. 실제 상태 불일치까지 재현한 항목은 아니다. target이 없을 때 commit하지 않는 Board 정책 등은 유지해야 한다.
반대로
createCanvasGestureSession은 이미 정본에 위임하는 wrapper다. Pointer capture/release를 관리하는 Web pointer session도 별도 책임이므로 같은 이름이라는 이유로 합치면 안 된다.6. 공개된 개념의 소유권과 필요성도 줄일 여지가 있다
Selection의
core/session.ts에 다음 계약이 공개되어 있다.SelectionSessionScopedSelectionSelectionEditIntentSelectionEditResultSelectionHistoryEntry앞의 네 가지는 레포 내 production 소비를 찾지 못했다. 마지막
SelectionHistoryEntry는 실제 EditingSession이 사용한다.분류: 앞의 네 가지는 필요성 미확인·축소 후보, History 계약은 소유권 검토 대상. 레포 내 소비가 없다는 사실만으로 외부 사용도 없다고 결론 내리거나 바로 삭제하면 안 된다. 실제 작업 경계와 History를 Editing이 소유하는 현재 구조에 맞게, Selection의 공개 계약이 무엇을 약속하는지 먼저 좁혀야 한다.
개념을 한 번 공개하면 기능 구현보다 오래 유지해야 할 수 있다. 사용 사례와 독립적인 불변 조건을 제시하지 못한 개념을 미리 동결하는 것은 최소성에 불리하다.
후보 판정 장부와 유지할 차이
isCompositionInput하이라키를 판단하는 기준
다음을 하나의 평면적인 기능 목록으로 분류하면 다시 겹친다. 대상의 종류, 작업의 수명주기, 입력 플랫폼, 기본 정책은 서로 다른 축이다.
이는 새로운 패키지 목록이나 일렬의 의존 계층을 추가하자는 제안이 아니다. 같은 규칙을 어디서 구현해야 하는지 판단하는 책임 지도다. Profile도 새로운 command bus나 상태 저장 runtime일 필요가 없다.
‘할 수 있다’는 최소한 세 가지를 구분해야 한다.
현재는 1에서 2, 2에서 3으로 넘어가는 연결이 일부 비어 있다. 따라서 기능을 모두 Core에 가져오는 것으로 해결되지 않는다.
권장 실행 순서
공유 API를 바꾸는 후속 작업의 완료 조건에는 owner의 export, 자체 API reference, site Usage, source registration, 소비자 연결과 의미 검증을 함께 포함해야 한다.
학습할 핵심은 같은 이름이 아니라 같은 입력·불변 조건·실패 의미·수명주기를 소유하는가다. 주소 해석은 같은 책임의 다른 구현이 실제 호환성 실패를 만든 사례다. 반대로 local/causal History는 이름이 같아도 제거하면 의미가 사라지는 차이다. 최소 프로토콜은 개념 수만 줄인 결과가 아니라, 필요한 차이는 표현하면서 공통 규칙의 소유자는 하나로 만든 결과여야 한다.
developer-1px commentedon Sep 8, 2026
건강도 감사의 첫 구현 단계를 #731 / PR #732로 진행했다.
주소 조회·JSON 검증을 Core 정본으로 연결하고 JSONPath·Zod·React·Clipboard의 재구현을 줄였다. 여섯 멤버의 document 계약은 유지하며, 기존 규칙을 소비할 수 있도록 stateless TypeScript API 두 개를 공개했다.
왜 전체 snapshot 복제 대신 stateless 조회가 필요한지, 공개 surface 두 개 증가와 중복 감소를 어떻게 구분했는지, 실패 시 선택·History 보존을 무엇으로 검증했는지는 구현·검증 기록에 정리했다.
다음 순서는 기존 감사의 2~4단계다: 단축키 기본 정책과 Annotation 책임, editor별 지원 행동·공통 적합성, 중복 수명주기·공개 개념의 축소 검토. Annotation Host 정리는 이미 열린 #589의 소유권을 먼저 확인해야 한다. 이번 PR은 첫 단계의 완료 증거이며 전체 Profile 동결의 증거로 확대하지 않는다.
developer-1px commentedon Sep 8, 2026
건강도 감사의 다음 구현을 #733 / PR #734로 올렸다. 기본 삭제·전체 선택·Undo/Redo의 수정키 판정을 기존 Web chord/resolver에 연결했다. 전체 선택 반복 정책과 Composer 제출 정책은 각각의 owner에 남겼고, public 함수·명령 종류는 늘리지 않았다.
구현 기록에는 같은 기본 규칙과 별도 정책을 구분한 이유, 기존 Composer 키 입력 API 보존에 따른 peer dependency 비용, native KeyboardEvent 속성을 다루는 검증을 정리했다. 영향 패키지 검증은 통과했으며 Site 로컬 전체 실행의 불안정성과 CI 진행 상태는 #733에 명시했다.
이전 PR #732의 소스 탭 기대값 누락도 수정했고 CI가 모두 통과했다. 두 PR 모두 열려 있으며 merge하지 않았다. 다음 책임 검토는 기존 #589의 Annotation 소유권과 연결해서 진행해야 한다.