Skip to content

앱 사례와 정착한 편집 관습에서 최소 프로토콜과 하이라키를 도출한다 #725

Closed

Description

@developer-1px

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의 선택 보존 수정은 기존 자산이다. 이번에는 새 동작을 추가하거나 미구현 사례를 완료했다고 표시하지 않는다.

검토 가능한 완료 증거

  1. 편집 사례별 대상·위치·선택·행위·중첩 맥락과 차이를 읽을 수 있다.
  2. 공통 후보마다 근거와 반례 또는 성립 조건이 있고, 공유 의미와 profile 정책을 구분한다.
  3. 의미의 분류, 계약의 구체화 관계, 실제 구현 의존 관계를 혼동하지 않는 하이라키를 제시한다.
  4. 기존 EG 규칙·owner·적합성 증거와 연결하며, 새로 도출한 사항의 실행 검증 여부를 명시한다.
  5. 문서 검사와 전체 diff 검토를 마치고 문서 PR로 제공한다. 조사 단계별 학습 댓글에는 확인 가능한 출처와 판단 요약을 남긴다.

Activity

  1. self-assigned this
    on Sep 7, 2026
  2. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    작업 계획과 읽는 방법

    이슈 본문의 Goal Anchor를 기준으로, 사례와 정착한 관습에서 최소 편집 계약·profile 차이·하이라키를 도출한다. 완료 증거는 근거와 반례가 연결된 설계 초안과 검증된 문서 PR이다. runtime·공개 API·Stable profile·package 배치는 그대로 유지한다.

    사례 수집
      → 같은 동사에서 다른 대상·결과 찾기
      → 공통 후보를 반례로 검토하기
      → 의미 분류 / 계약 구체화 / 구현 의존 관계 구분하기
      → 기존 EG 규칙과 연결하고 문서 검증하기
    

    댓글마다 확인한 사실, 설계 후보와 판단 요약, 기각한 대안, 검증 결과, 다음 질문을 기록한다. 구현 완료 여부와 새 제안의 검증 여부를 구분한다. 독자가 원문과 코드를 보고 결론을 재검토할 수 있는 학습 기록을 목표로 한다.

    학습의 첫 질문은 **같은 Delete가 문자 제거·셀 값 비우기·행 제거로 달라져도 무엇이 같은 편집 문법인가?**이다. 단어 목록의 교집합만 뽑으면 이 차이를 잃고, 기능의 합집합을 만들면 작은 Core를 잃는다. 대상과 결과의 관계를 먼저 살펴본다.

    검증은 docs:evaluate, 문서 링크·코드 근거 확인, 전체 diff의 범위·모순 검토로 한다. 현재 문서만 변경하므로 새 runtime 테스트나 브라우저 인증을 완료 증거로 대신하지 않는다. 기존 적합성 테스트는 문서에 연결된 현재 증거를 확인할 때 사용한다.

    관찰된 위험은 두 가지다. 여러 내부 editor가 공통 Session을 쓴다는 사실을 독립 구현의 합의로 오해할 수 있고, 현재 구현의 제한을 영구 표준으로 굳힐 수 있다. 각 사례의 증거 수준과 반례를 함께 기록해 판별한다.

  3. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 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에 계속 추가하는 방식도 장기 약속의 범위를 불필요하게 키운다.

    읽을 자료와 확인할 질문.

    • Apple HIG 1992, 인쇄 쪽수 286–300: PDF 뷰어에서는 310–324쪽(1부터 세는 쪽수)에 해당한다. “선택”이라는 단어 아래 어떤 종류의 대상을 구분하는지 읽어볼 수 있다.
    • Microsoft 표준 메뉴: 명령 어휘의 일관성과 그 명령의 대상별 의미는 어디서 갈라지는가? Windows 7 시대 지침이라는 범위를 유지한다.
    • Sheet 구현, Database 구현: cut과 record.delete가 실제로 바꾸는 값을 비교하면 차이가 보인다.

    다음 검토는 이 공통 후보가 성립하지 않는 편집기를 찾는 것이다. 반례는 설계의 실패를 숨길 이유가 아니라, 영구 계약의 범위를 정할 증거다.

  4. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 2 — 반례로 공통 규칙의 적용 범위를 좁히기

    관찰한 반례.

    처음 떠올리기 쉬운 일반화 확인한 반례 설계에 남길 구별
    선택 작업은 언제나 Undo 대상이 아니다 GIMP는 Scissors Select로 선택을 완성한 작업과 Quick Mask 전환의 Undo를 설명한다 현재 레포의 일시적 Selection과 raster 선택 제작의 History 정책
    이동은 Copy → 즉시 제거 → Paste다 Finder는 Clipboard에 있는 파일을 붙여넣는 시점에 원래 위치에서 이동하는 동작을 제공한다 현재 EG-CUT의 즉시 제거 계약과 다른 transfer profile
    복사는 저장 값을 그대로 옮기면 된다 Excel은 수식을 복사할 때 상대 참조를 바꾸지만 수식 이동에서는 참조를 유지한다 payload의 보존 의미와 대상 위치에 따른 재해석
    모든 편집은 미리 선택된 객체가 필요하다 레포의 annotation.create는 새 annotation을, event.create는 시간 구간을 직접 받는다 Selection에서 얻는 대상, 명시 대상, 삽입 위치

    판단. “내용을 바꾸지 않는다”와 “History에 남기지 않는다”는 서로 다른 명제다. 현재 EG-SELECT/EG-HISTORY는 레포의 기존 Selection·Editing 동작을 설명하고 실제 테스트가 있다. 이 계약을 깨지 않고 적용 범위를 명시할 수 있다. GIMP를 같은 profile이라고 선언하거나, 반례를 수용한다며 기존 테스트의 의미를 바꾸지는 않는다.

    기각한 대안. 예외를 전부 Host-specific으로 밀어내면 사람이 이미 사용하는 편집 문법을 프로토콜에서 잃는다. 반대로 모든 차이를 즉시 Core의 새 기능으로 수용하면 공통 계약이 기능 목록이 된다. 의미가 다른 경우 profile의 성립 조건으로 설명하고 그 owner에서 검증할 질문을 남기는 편이 맞다.

    공부할 자료.

    • GIMP Undoing: 무엇이 문서의 내용이고 무엇이 복원할 작업인지 서로 다른 질문임을 보여준다. 이 공식 문서의 모든 세부 동작을 직접 실행 검증한 것은 아니다.
    • Apple Mac 단축키 — Finder: Option-Command-V의 Finder 이동 의미를 텍스트 편집의 같은 키 조합과 비교할 수 있다.
    • Excel 수식 이동·복사: 값의 동일성과 참조 의미의 보존이 달라지는 작은 사례다.
    • Annotation의 명시적 생성 의도: selection.set과 annotation.create의 입력을 비교해 볼 수 있다.

    이번 관찰은 새 raster/file editor를 구현하자는 범위 확장이 아니다. 기존 11개 사례만으로 보편성을 주장할 수 없음을 드러내는 외부 반례다.

  5. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 3 — 하이라키에서 ‘종류’, ‘조합’, ‘의존’을 구별하기

    관찰. APG Grid는 셀 탐색과 내부 caret 조작을 구분한다. Keynote도 텍스트 상자 자체를 선택하는 상태와 내부 글을 편집하는 상태를 구분한다. 레포에서는 DocumentTextControl이 native range를 투영하고, registerWebVirtualSelectionScope는 전체 텍스트 선택·Copy 영역과 editable target 우선 처리를 맡는다. 부분적인 소유자는 이미 존재한다.

    설계 후보.

    공통 편집 규칙
      ├─ 대상별 구체화: model · position · selection · 연산 · 교환 · 복원
      └─ 입력별 구체화: key · pointer · IME · focus · 중첩 · lifecycle
                  │ 두 축을 조합하고 함께 검증
                  v
             Hands profile
                  │ 여러 Hand와 외부 서비스를 조합
                  v
           Application / Host
    

    이것은 계약이 구체화되는 관계다. Core → Editing → Hands → App처럼 읽는 순서나 package import graph만으로 이 관계를 대신할 수 없다. Sheet가 Rich Text를 상속하는 것도 아니고, 셀 편집을 시작할 때마다 별도 History를 만들어야 한다는 뜻도 아니다.

    분리해서 남긴 용어.

    • Selection range의 focus: 범위의 한 endpoint.
    • 입력 focus: 지금 입력을 받는 곳. Toolbar로 옮겨져도 명령의 편집 대상이 사라지는 것은 아니다.
    • Calendar scope: "this" | "this-and-following" | "all": 반복 일정의 변경 범위. 입력을 받을 편집 맥락과 다르다.
    • JSONDocument의 주소: 현재 JSON 값 안의 위치. 같은 대상의 identity나 DOM 위치와 같다고 가정하지 않는다.

    기각한 대안. 모든 중첩을 범용 Scope 클래스 하나로 선언하면 DOM focus, model subtree, History 귀속을 우연히 묶을 위험이 있다. 이번에는 실제 필요한 진입·수신자·거절·복귀 규칙을 사례로 명시하고 새 runtime 추상화는 만들지 않는다.

    검증할 반례. 내부 text editor가 Delete를 거절했을 때 바깥 객체가 삭제된다면, 두 editor 각각의 단위 테스트가 통과해도 조합 계약은 실패한다. 따라서 현재의 원자적 편집 테스트와 별도로 중첩 수신자·실패 전파를 관찰해야 한다. 이번 문서에는 이 사례를 미실행 후보로 표시한다.

    읽을 자료.

    • APG Grid — 셀 내부 편집: 같은 키를 두 편집기가 동시에 처리할 수 없는 이유를 볼 수 있다.
    • Keynote의 텍스트 상자: 객체 선택과 내부 텍스트 편집을 비교할 수 있다.
    • W3C Selection API의 Background: 새 절충안을 만들었다가 기존 구현들과 맞지 않아 되돌린 역사를 명세 자체가 설명한다. 현재 문서는 Working Draft다. ‘단순한 설계’와 ‘이미 쓰이는 계약에 맞는 설계’가 다를 수 있다는 사례로 읽으면 좋다.
  6. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 4 — 근거의 강도와 설계의 강도를 맞추기

    외부 자료와 내부 구현을 비교한 결과를 다음처럼 구분했다.

    판단 대상 근거와 수준 이번 설계의 판단
    선택·편집·교환·복원이라는 오래된 어휘와 역할 Apple 1992 지침, Windows 표준 메뉴, 현재 제품 설명. 역사적 지침과 반복된 관습 stable: 공통 의미를 도출할 기반. 모든 세부 동작의 동일성을 뜻하지 않음
    객체·셀 전체와 내부 텍스트를 구별하는 조작 Apple의 표/그래픽 설명, APG Grid, Keynote. 제품 관습과 구현 지침 stable: 중첩에서 입력 수신자를 구별할 근거. 범용 Scope API 채택 근거는 아님
    정확한 History 단위·selection 기록·transfer 시점 GIMP 선택 도구, Finder 이동, 레포의 typing/gesture/local History contested: 맥락에 따라 서로 다른 관습이 타당함. Profile이 명시해야 할 부분
    이 레포의 단일 editing API가 외부 표준이라는 주장 내부 11개 사례와 세 editor의 공통 runner absent: 같은 profile의 독립 구현 합의에 대한 증거가 아직 없음

    초안 리뷰에서 보완한 점. 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를 이슈의 완료 조건과 대조한다. 문서의 분량 증가 비용을 줄이기 위해 중복된 책임 흐름 그림은 하나로 합쳤다.

  7. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 5 — 초안을 검증 가능한 약속으로 바꾸는 마지막 검토

    원문을 다시 대조하니 Apple HIG 1992 인쇄 쪽수 290–291에도 Shift-click 확장의 addition과 fixed-point 방식이 함께 나온다. 그래서 EG-SELECT의 anchor 보존을 “anchor가 있는 모든 범위 선택”에 적용한다고 읽힐 문장을 현재의 고정 anchor 전이로 좁혔다. 기존 EG 문장과 구현을 바꾼 것은 아니다. 학습 1의 PDF 뷰어 쪽수 안내도 1부터 세는 쪽수 기준으로 바로잡았다.

    이 사례가 보여주는 검토 방법은 다음과 같다.

    1. 공통 후보를 한 문장으로 쓴다.
    2. 오래된 지침과 현재 구현에서 반례를 찾는다.
    3. 타당한 반례가 있으면 성립 조건을 명시하거나 profile이 결정할 부분으로 분리한다.
    4. 기존 profile의 소비자 결과가 유지되는지 확인한다.
    5. 새 후보는 시작 상태·작업·관찰 결과로 적고, 미검증 항목을 통과 결과에 섞지 않는다.

    대안 비교의 결론. 기존 구현 이름만 하나로 합치면 의미의 차이가 사라지고, 모든 차이를 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 귀속은 문서의 검증 질문으로 남아 있다.

  8. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    결과와 학습 순서

    PR #726에 설계 초안을 정리했다. 최종 commit은 c8570dc7이며 CI Plan·Package·Site가 통과했다. External kit은 이번 변경에 대한 실행 계획에서 skipped다. 문서 검사, 기존 공통 적합성 51개 테스트, 내부 링크 28개와 GitHub 렌더링의 표 10개·코드 블록 5개도 확인했다.

    이 순서로 읽으면 설계가 어떻게 도출됐는지 따라갈 수 있다.

    1. 오래된 명령과 오래된 의미를 구별하기
    2. GIMP·Finder·Excel 반례로 공통 규칙의 범위 좁히기
    3. 하이라키의 종류·조합·의존 구별하기
    4. 근거의 강도에 맞춰 설계 판단하기
    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 귀속이다. 이 질문들을 구현 완료로 표시하거나 후속 구현 이슈로 자동 확대하지 않았다.

  9. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    추가 조사 — 조합 경계를 30분 더 살펴보기

    사용자가 “30분만 더 조사 위주로 진행해 지금처럼 이슈에다가 읽을 거리 주는 식으로” 요청했다. 앞의 설계 초안과 학습 기록을 이어서, 다음 질문을 조사한다.

    1. 내부 텍스트와 바깥 셀·객체가 함께 있을 때, 어떤 편집기가 입력을 받고 언제 위임·거절·복귀하는가?
    2. 편집 맥락이 바뀌면 Undo의 대상과 작업 단위는 어떻게 정해지는가?
    3. 서로 다른 편집기 사이에서 Copy/Paste가 보존하는 의미와 손실·실패는 어떻게 약속되는가?

    대상은 인간의 편집 동작과 이를 연결하는 protocol이다. 1차 비교 대상은 플랫폼의 공식 command routing·편집·History·Clipboard 계약과 실제 제품 지침이다. 독립 editor framework의 공개 구현은 이 계약을 실현하는 형태를 비교할 때 사용한다. 라이브러리의 최신 API 모양을 오래된 보편 문법의 증거로 쓰지 않는다.

    표준(standard), 권장 지침(bp), 반복된 관습(de-facto), 아직 수렴하지 않은 제안(frontier)을 구분한다. 댓글에는 읽은 원문이 무엇을 입증하는지와 한계, 작은 비교 사례, 레포와의 연결을 남긴다.

    이번 회차는 조사와 학습 기록에 집중한다. 기존 PR #726은 설계 초안으로 유지하며 runtime·public API·package 변경과 merge는 진행하지 않는다. 발견한 사항을 후속 구현 이슈로 자동 확대하지 않는다.

  10. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 6 — 명령을 보낸 곳, 받을 곳, 실행 가능 여부는 별개의 질문이다

    읽은 근거. Cocoa는 명시된 target으로 action을 보내거나, target이 없으면 responder chain에서 수신자를 찾는다. WPF는 command source·target·parameter를 구분하고 CanExecute로 현재 실행 가능 여부를 질의한다. GTK의 action은 이름·enabled 상태·인자 type을 갖고 application/window/widget에 귀속된다. 서로 다른 플랫폼의 공개 계약에서 같은 책임 구별이 반복된다.

    Toolbar 버튼 / 메뉴 / 키 입력
              │ 명령을 요청
              v
         수신할 편집 대상 결정
              │ 현재 상태에서 실행 가능한가
              v
         해당 대상의 편집 실행
              │
              v
         성공·거절 결과를 관찰
    

    작은 예제. 문서 A에서 문장을 선택한 뒤 Toolbar의 Copy 버튼을 누른다. 클릭을 받은 곳은 버튼이지만, 복사할 내용은 A가 가진 선택이다. 따라서 “입력 focus 하나가 모든 대상과 상태를 대표한다”는 해석은 부족하다. WPF는 키보드 focus를 잃어도 영역 안의 logical focus를 기억할 수 있는 구조도 설명한다.

    레포에 대한 판정. 앞의 초안에서 구별한 Selection·입력 수신자의 방향은 외부 계약에 close하다. 다만 지금의 Scope라는 새 타입 하나로 모두 묶을 근거는 더 약하다. GTK에서 action의 target은 인자 값을 뜻하는 문맥도 있어, 다른 플랫폼의 같은 이름을 그대로 대응시키면 오히려 의미가 틀어진다.

    Cocoa의 menu validation은 수신자를 먼저 찾은 뒤 그 대상의 실행 가능 여부로 메뉴를 활성화한다. “메서드가 있다”, “지금 할 수 있다”, “실제로 성공했다”를 같은 상태로 읽지 않게 한다. 이 사실만으로 모든 플랫폼이 동일한 실패 전파 규칙을 제공한다고 단정할 수는 없다.

    근거의 수준. 각 자료는 특정 플랫폼의 공식 API 계약 또는 지침이다. 세 플랫폼에서 역할 구별이 반복되는 것은 안정된 설계 관습의 근거지만, 하나의 범용 command API나 wire format의 표준을 입증하지는 않는다.

    읽을거리와 관찰 포인트.

    다음 질문은 수신자를 결정한 뒤의 거절이 다른 편집기로 넘기는 신호와 어떻게 다른가이다. API 모양을 통일하는 것보다 먼저 검증해야 하는 조합 의미다.

  11. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 7 — ‘적용되지 않음’, ‘편집 거절’, ‘이벤트 차단’을 같은 실패로 묶으면 안 된다

    명령 후보를 이어서 찾는 동작은 정착한 구현 방식이다. 이미 맡은 편집의 거절을 다른 대상으로 재해석하는 동작과 구별해야 한다. 앞선 초안의 중첩 편집 규칙을 적용할 때 필요한 조건이다.

    ProseMirror의 공식 Commands 안내는 적용할 수 없는 명령이 아무 변경 없이 false를 반환하도록 한다. chainCommands는 첫 성공 후보까지 순서대로 시도한다. 기본 Backspace도 선택 삭제 → 뒤쪽 블록 결합 → 앞 노드 선택이라는 후보들을 거친다. 이것은 여러 편집을 모두 수행하는 transaction 묶음이 아니다. 따라서 “Backspace에는 하나의 동작만 있다”, “fallback은 언제나 잘못이다”라는 일반화는 반례를 만난다. ProseMirror Guide — Commands

    DOM은 이벤트 전파 중단과 기본 동작 취소를 별개의 flag로 정의한다. defaultPrevented는 취소 flag를 알려주며, 우리 document commit의 성공 여부를 표현하지 않는다. DOM Standard — Event

    이를 현재 레포의 계약과 대조하면 세 질문이 드러난다. 아래 표는 새 반환 타입 제안이 아니라 사례를 판별하는 표다.

    상황 다음에 확인할 질문 현재 확인 가능한 근거
    이 명령 후보가 현재 선택에 적용되지 않음 다른 후보가 같은 맥락에서 적용되는가? ProseMirror의 명령 연결
    이 Web binding이 paste 형식을 지원하지 않음 native 처리 또는 다른 명시적 수신자가 맡는가? 현재 Web 테스트는 편집 callback과 preventDefault를 호출하지 않음
    지원하는 paste를 맡았지만 편집이 거절됨 거절 결과와 기존 document 상태가 보존되는가? 현재 Web 테스트는 기본 동작 취소 후 editing.rejected를 확인
    이벤트 전파를 중단함 기본 동작도 취소해야 하는가? 편집 결과는 무엇인가? DOM의 별개 flag이므로 별도 판단 필요

    로컬 읽기: clipboard-rejection.test.ts. 이번 라운드에서는 테스트 내용을 읽어 대조했으며 재실행하거나 중첩 브라우저 동작을 재현하지 않았다.

    초안의 후보 규칙은 다음처럼 좁혀 읽는 편이 정확하다.

    수신자가 편집을 맡고 거절했다면, 별도로 정의한 위임 계약 없이 그 거절을 바깥 대상의 다른 편집 허가로 해석하지 않는다.

    이것은 모든 플랫폼에서 증명된 보편 규칙이 아니라 현재 설계의 보존 후보다. 특히 ProseMirror의 false는 ‘후보가 적용되지 않는다’는 의미이며 우리 EditingResult.ok: false와 자동으로 대응하지 않는다. 두 boolean을 기계적으로 연결하면 위 표의 구별을 잃는다.

    근거 강도: DOM 이벤트 구별은 해당 플랫폼의 standard; ProseMirror 연결은 해당 구현의 공개 계약이며 인접 비교 대상이다. 중첩 편집의 거절 이후 경로에 대한 생태계 전체 합의는 아직 absent로 둔다. 이 레포가 선택할 안전한 계약과 외부에서 이미 정착한 규칙을 구별한다.

    읽으면서 확인할 질문: 셀 내부의 텍스트 삭제가 거절되었을 때, 셀 전체를 지우는 것은 같은 명령의 다음 후보인가, 수신 대상이 달라지는 새 명령인가? 코드 설계 전에 이 경계가 사례로 답해져야 한다.

  12. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 8 — Undo의 공통 문법은 오래됐지만, History의 범위는 하나로 굳지 않았다

    후속 정리: 사용자와 확인한 방향은 편집 Undo 시 선택을 함께 복원하는 기본 Profile을 제공한다는 것이다. 아래의 다양한 History 정책은 그 기본값의 적용 범위와 변형을 설명한다. 사용자 전제 정리, 기본값을 뒷받침하는 구현 근거

    Undo를 제공한다는 약속과 ‘어떤 기록을 한 번 되돌리는가’라는 약속을 분리해야 한다. 입력 focus, 기록의 소유자, 기록에 포함할 변경, 한 step의 묶음은 서로 다른 결정이다.

    읽은 근거 실제로 정하는 것 일반화하면 안 되는 것
    AppKit Undo Architecture responder chain에서 manager를 찾고 문서 manager나 view 전용 manager를 사용할 수 있음. 기본 field/cell 편집 기록에는 focus 수명과 연결된 동작도 있음 모든 view마다 반드시 별도 History를 생성한다는 규칙
    Qt QUndoGroup 여러 stack 가운데 active stack을 명시적으로 선택하고 공통 Undo/Redo action을 연결 focus 이동 자체가 기록 소유권·수명을 자동 결정한다는 규칙
    Yjs UndoManager shared type 범위, trackedOrigins, 시간 기반 묶음과 stopCapturing()을 구별 Undo가 항상 전역 문서의 직전 snapshot 전체를 복원한다는 규칙

    AppKit 문서는 2011년의 공식 아카이브다. 당시의 설계 근거로 읽으며 현재 모든 macOS 앱의 동작이라고 주장하지 않는다. Qt는 독립적인 현재 native framework 계약이다. Yjs는 협업 구현이라는 인접 비교 대상이며 이것만으로 협업 Undo의 유일한 표준을 입증하지 않는다.

    Undo 요청
       |
       +-- 어느 History를 실행하는가?       수신·routing
       +-- 어떤 변경을 기록해 두었는가?     문서 범위·origin·정책
       +-- 무엇을 한 번에 되돌리는가?       grouping
       +-- 내용 외 무엇을 복원하는가?       selection·view 상태
       +-- 외부 변경이 끼어들면 어떻게 하는가? 복원 알고리즘·유효성
    

    기존 초안에서 한 가지 설명은 더 좁혀야 한다. ‘일시적 selection이므로 Undo 대상이 아니다’도 보편 명제가 아니다. AppKit은 document 상태에 포함하지 않는 view selection도 사용자 편의를 위해 Undo에 등록할 수 있다고 설명한다. 이는 앞서 본 GIMP의 mask 제작보다 직접적인 반례다. ‘저장되는 상태인가?’와 ‘Undo로 되돌릴 상태인가?’는 별개 축이다. 같은 AppKit 문서의 Undo and the Control and View Layers

    현재 레포와의 거리:

    • EditingHistory를 교체 가능한 owner로 둔 방향은 위 사례들과 close하다. history.ts
    • 현재 selection-only는 문서 History entry를 만들지 않으며, 외부 document 변경은 local inverse History를 비운다. 이는 명시된 구현 정책이다. 모든 편집기의 역사적 공통 규칙으로 승격할 근거는 없다. session-history.test.ts
    • 같은 문서를 보는 A/B view가 어떤 manager를 공유하고 Undo 후 어느 view의 selection을 복원할지는 아직 unknown이다. 현재 owner 연결 API가 있다는 사실과 그 조합의 동작이 검증됐다는 사실은 다르다.

    판정: ‘명령과 History 수신처를 구별한다’는 설계 경향은 stable; 모든 문서·view·selection에 적용할 단일 History 범위는 absent다. 기존 EG-SELECT·EG-HISTORY는 현재 profile의 계약으로 보존하되, 다른 profile의 적합성을 판정할 때 이 정책을 보편 전제로 쓰지 않아야 한다.

    읽을 때의 사고 실험: 같은 문서에서 A는 문장을 쓰고 B는 객체를 옮겼다. A로 돌아와 Undo하면 ‘B의 마지막 변경’, ‘A의 마지막 변경’, ‘A의 현재 입력 draft’ 중 무엇을 되돌리는가? 정답을 먼저 하나 고르는 대신 각 동작에 필요한 History 귀속 계약을 적어 보면 하이라키가 드러난다.

  13. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 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

    원본 편집기의 대상
            |
           Copy
            |
      교환 가능한 표현들
      +-- 원본 구조 표현
      +-- HTML 등 교환 표현
      +-- plain text
            |
      수신 가능한 표현 선택
            |
      대상 model·schema·위치에 맞춰 해석
            |
          Paste 편집
    

    위 트리는 설명용이다. 모든 editor에 HTML이나 특정 JSON schema를 강제하는 제안이 아니다. 여러 item과 한 item의 여러 표현도 같은 개념이 아니다.

    여기에 중요한 반례가 있다. 가장 풍부한 표현을 읽었다고 사용자가 원하는 Paste 의미까지 결정되는 것은 아니다. Word는 같은 문서/다른 문서/다른 앱에서의 붙여넣기 설정을 구별하고, 원본 서식 유지·서식 병합·텍스트 전용을 제공한다. 즉, 표현을 읽을 수 있는 능력과 어떤 변환을 원하는지라는 정책은 다르다. Word — Control the formatting when you paste text

    현재 레포에서는 이 구별의 일부가 이미 보인다.

    단계 확인한 현재 동작 남은 계약 질문
    표현 만들기 Rich Text가 구조·HTML·plain 표현을 순서대로 제공 각 표현이 무엇을 보존하고 무엇을 잃는가?
    읽을 표현 찾기 Web binding은 우선순위에 따라 첫 유효한 decode를 선택. 잘못된 JSON 뒤 HTML 선택 테스트가 있음 ‘해석 불가’와 ‘사용자에게 중요한 의미가 손실됨’을 어떻게 구별하는가?
    실제 붙여넣기 payload를 선택한 뒤 editor의 paste를 실행. 그 편집이 거절되면 다른 표현을 자동 재시도하지 않음 거절 이후 더 단순한 표현으로 바꾸는 경우는 별도 정책·새 시도인가?
    외부 교환 현재 테스트는 정해진 payload/표현 사례를 검증 서로 다른 독립 editor의 실제 교환과 원본 ID·참조·schema 처리까지 검증했는가?

    로컬 읽기: Rich Text 표현, Web 표현 선택 테스트, Web binding.

    비교 판정: 여러 표현과 editor별 수신 해석을 둔 현재 방향은 close; 하나의 공통 wire schema로 모든 편집 장르를 통일한다는 근거는 absent다. 같은 format 이름만으로 내용 의미까지 호환된다고 인증해서도 안 된다.

    읽을 때의 질문: 굵은 글씨가 있는 표를 문자열 입력창에 붙여넣으면 무엇을 보존해야 하는가? ‘문자열만 받는 대상’과 ‘표를 지원하지만 지금은 읽기 전용인 대상’에서 fallback을 같은 이유로 실행해도 되는가? 이 구별이 학습 7의 ‘후보 탐색과 거절’에 연결된다.

  14. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 10 — 사용자 전제 보정: 유연한 기반 위에, 정착한 default를 Profile의 계약으로 제공한다

    조사 중 사용자가 의도를 더 명확히 했다. Core는 여러 정책을 수용할 수 있게 유지하고, 사람들이 이미 익숙한 편집 동작은 기본 Profile로 제공한다. Cmd+Z → Undo, 편집 Undo 시 선택 영역의 복원이 대표 예다.

    이 전제를 이후 판단의 기준으로 삼는다. 학습 7–9의 반례는 기본값을 포기할 이유가 아니라, 기본 Profile의 적용 범위와 변형을 가르는 근거다. 예외가 존재한다는 사실만으로 널리 정착한 기본 동작을 계속 미결정 상태에 두지 않는다.

    프로토콜 기반
      |  여러 model·입력·History 정책을 수용하는 계약
      |
      +-- 기본 Profile
      |     정착한 편집 관습을 구체적인 기본 동작으로 약속
      |     입력 → 의도 → 결과·선택·History까지 검증
      |
      +-- 명시적인 다른 Profile 또는 허용된 선택
            다른 정책이 필요한 맥락의 차이를 설명
    

    이는 설명상의 구분이며 새 package나 중앙 profile registry를 만들자는 제안이 아니다. 기존의 대상별 계약과 입력별 계약을 조합해 Hands profile로 검증하는 구조 안에서 구체화할 수 있다.

    특히 Undo에 대해 두 가지를 분리한다.

    질문 이번에 확인한 사용자 의도와 기본 계약 후보
    편집을 Undo하면 무엇이 돌아오는가? 문서 내용과 편집 전 선택을 함께 복원하는 것을 기본으로 제공
    선택만 이동해도 새 Undo step을 만드는가? 별도의 History 정책. 앞의 선택 복원 약속과 독립적으로 정할 수 있음
    Cmd+Z는 무엇을 뜻하는가? macOS 기본 입력 계약에서 Undo. 어떤 History가 수신하는지는 조합된 편집 맥락의 계약

    ‘선택 영역도 Undo에 포함’은 우선 편집과 함께 선택을 복원한다는 뜻으로 이해했다. 선택 이동을 독립 Undo step으로 기록하자는 요구로 확대 해석하지 않는다.

    기본 Profile을 쓰는 사용자에게는 이것이 실제로 믿을 수 있는 약속이어야 한다. 따라서 이후 기본 동작을 바꿀 때도 호환성을 검토해야 한다. 확장이 가능하다는 이유로 같은 Profile 이름 아래 관찰 가능한 동작을 임의로 바꾸면 안정화 목표를 잃는다. 다만 어느 옵션을 Profile 안에서 허용하고 어느 차이를 다른 Profile로 식별할지는 구체적 사례로 정할 사항이다.

    이후 조사 질문도 ‘모든 앱이 반드시 똑같은가?’에 머무르지 않고, **‘어떤 동작을 기본으로 제공할 근거가 충분하며, 어떤 차이를 명시해야 사용자의 예상이 보존되는가?’**로 좁힌다.

    이번 댓글은 사용자의 설계 전제를 기록한 것이다. 런타임·공개 API·기존 PR은 변경하지 않았다.

  15. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 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 History

    CKEditor의 사용 안내도 Windows 계열 Ctrl+Z와 macOS Cmd+Z를 Undo의 익숙한 입력으로 설명한다. 두 editor를 전체 편집 장르의 유일한 표준으로 삼지는 않지만, 사용자가 제시한 default를 뒷받침하는 독립 구현의 신호로 볼 수 있다. CKEditor — Undo/Redo

    기본 계약 후보 지금 채택할 수 있는 의미 명시할 조건·변형
    플랫폼의 익숙한 Undo 키 macOS Cmd+Z, Windows 기본 Ctrl+Z → Undo 의도 현재 맥락의 History 수신처, composition 중 처리
    편집과 선택의 함께 복원 Undo → 편집 전 내용·선택, Redo → 편집 후 내용·선택 외부 변경이 끼어든 경우의 유효한 위치 mapping, 여러 view의 귀속
    사용자 작업 단위 타이핑·drag 등의 여러 내부 변경을 의미 있는 Undo step으로 제공 typing 시간 간격·단어/위치 경계·gesture 경계의 정확한 기준
    셀 탐색과 내부 편집 구별 셀 내부 편집 중에는 화살표를 내부 입력에 사용하고 탐색으로 복귀하는 경로를 제공 Enter/F2 진입과 복귀의 구체적 선택, Escape가 draft도 취소하는지

    마지막 행은 APG Grid의 Editing and Navigating Inside a Cell을 읽은 결과다. APG는 여러 관습을 허용하는 bp 자료다. 그중 하나를 기본 Profile로 고를 수 있으며, 그 선택을 모든 셀 입력기의 유일한 법칙이라고 설명할 필요는 없다.

    현재 레포는 이미 내용과 before/after selection을 함께 복원하는 테스트를 가지고 있다. session-history.test.ts. 따라서 이 기본 계약은 처음부터 새로 발명해야 하는 상태가 아니다. 아직 빈 곳은 이 의미를 입력·중첩·여러 view 조합에서도 같은 계약으로 검증하는 부분이다.

    하이라키에서 Profile은 선택한 규칙과 적합성 기준을 묶는다. 구현 책임은 기존 canonical owner에 남는다.

    기본 Profile이 약속하는 한 동작
       |
       +-- 플랫폼 입력 해석             Web·Affordance
       +-- Undo 실행과 결과·선택 연결   Editing
       +-- 기록할 변경과 복원           선택한 History owner
       +-- 이 조합의 관찰 결과 검증     Profile 적합성 사례
    

    이 기본값을 제공하기 위해 저수준 JSONDocument Core에 키보드나 모든 History 정책을 넣을 필요는 없다. 작은 기반과 정착한 기본 동작을 함께 유지할 수 있다.

    학습용 확인 사례: Alpha의 ph 선택 → X로 교체 → Undo → Alpha와 ph 선택 복원 → Redo → 교체 후 내용·선택 복원. 이 사례를 어느 공개 API 조합으로 실행하고 관찰할 수 있는지가 Profile의 구체적인 약속이 된다. 이 전체 입력 시나리오는 이번 라운드에서 실행한 테스트가 아니라, 기존 근거를 바탕으로 적은 적합성 후보다.

  16. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 12 — 기본 Cut 계약을 검증할 때는 callback 뒤의 native 동작도 관찰해야 한다

    ‘payload 확보가 실패하면 원본을 제거하지 않는다’는 기본 계약을 제공하되, 검증 범위를 editor callback 밖까지 잡아야 한다. 이것은 기본값을 미루는 이유가 아니라 그 약속을 실제 환경에서 입증할 조건이다.

    현재 createWebClipboardBinding.cut()은 다음 순서다.

    payload 읽기 → 표현 encode·setData
                      |
                      +-- 실패 → 실패 반환
                      |
                      +-- 성공 → preventDefault → editor cut → 편집 결과
    

    읽은 코드상 쓰기 실패 분기는 이 binding 안에서 preventDefault()를 호출하지 않는다. 기존 테스트는 쓰기 실패 시 editor의 제거 callback이 호출되지 않고 document/selection/history가 그대로임을 확인한다. Clipboard는 메모리 객체로 대체되어 있다. Web binding, clipboard-rejection.test.ts

    W3C 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에서 실패 상황을 직접 재현했다는 뜻은 아니다.

    추가로 확인할 사례 관찰해야 할 것
    지원하는 Cut에서 첫/두 번째 표현 encode 또는 쓰기 실패 binding 결과, event 취소 상태, 후속 native 편집, 실제 document·selection·History
    표현을 준비했으나 editor 제거 거절 원본 보존, 실패 결과, clipboard에 남은 표현을 따로 관찰
    지원하지 않는 입력을 native에 위임 위임된 결과가 Profile의 약속과 일치하는지

    특히 Rich Text binding에는 cut listener 외에 beforeinput(deleteByCut) 처리도 있다. 그러므로 후속 경로까지 포함한 판정이 필요하다. contenteditable.ts

    이번 발견은 재현 전 검증 공백으로 기록한다. 특정 브라우저에서 실제 데이터 손실을 확인한 확정 버그로 등록하지 않는다. 해결 방향을 곧바로 ‘더 일찍 모든 이벤트 취소’로 결정하지도 않는다. 입력을 맡은 실패와 명시적 native 위임의 경계를 먼저 적용해야 하기 때문이다.

    현재 초안의 ‘OS clipboard와 document 사이의 분산 transaction을 약속하지 않는다’는 한계는 유지된다. 그 안에서도 원본 제거 조건과 실패 결과는 기본 Profile이 명확히 보장할 수 있다.

  17. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 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

    입력 중 표시·조합 상태
            |
      관찰·확정 또는 취소
            |
      문서에 반영할 편집 결과
            |
      Profile이 정한 Undo 작업 단위
    

    이 구별이 있으면 ‘실패한 편집은 자신의 partial document mutation을 남기지 않는다’는 계약과 입력 중 임시 표시를 함께 설명할 수 있다. native 표시가 잠시 달랐다는 사실만으로 확정된 JSON document가 이미 변경됐다고 보지 않는다. 반대로 입력 계층은 확정·거절·취소 이후 표시와 model을 다시 맞출 책임이 있다.

    현재 레포에는 ㅎ → 하 → 한으로 DOM을 변화시킨 뒤 한 번의 Undo로 원래 내용이 돌아오는 사례와, 조합이 원래 DOM으로 돌아왔을 때 새 Undo 기록이 생기지 않는 사례가 있다. 이는 합성 이벤트와 DOM fixture를 사용하는 테스트이며 실제 OS IME 세션 검증과 구별한다. Rich Text composition 테스트

    자료를 읽는 방법에서도 유용한 사례가 나왔다. 다음 두 발행 초안은 compositionupdate와 beforeinput의 순서를 다르게 서술한다.

    확인한 발행본 해당 절의 서술
    UI Events, 2026-02-21, 3.6.6 beforeinput → compositionupdate → input
    Input Events Level 2, 2026-05-01, 7 compositionupdate → beforeinput → input

    이 차이만 보고 ‘현재 브라우저가 서로 합의하지 못했다’고 결론 내리면 안 된다. w3c/uievents #354의 본문뿐 아니라 마지막 댓글까지 읽으면, 2023-12-08에 Chromium 변경의 web compatibility를 확인했고 spec 갱신을 요청했다는 기록이 나온다. 현재 열린 이슈라는 표시와 실제 구현 수렴 상태는 별개일 수 있다. 마지막 확인 댓글

    판정: 진행 중 입력·확정된 편집·History 작업 단위를 구별하는 현재 방향은 외부 모델과 close하다. 이 자료만으로 2026년 모든 브라우저/OS/IME의 실행 순서를 인증할 수는 없다. 안정화할 기본 의미를 정한 뒤 실제 환경별 입력 trace가 그 의미로 귀결되는지 검증하는 순서가 적절하다.

    다음 검증 후보는 범위가 작다: 조합 완료 후 Undo, 조합 취소, 조합 중 Undo 입력, 조합 중 focus 이동. 각 경우에 내용·선택·History·입력 상태가 어떻게 끝나야 하는지를 먼저 적는다. 이것은 브라우저의 특정 지연 시간 상수를 Core 계약으로 올리자는 제안이 아니다.

  18. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    추가 조사 결과와 읽기 순서 — 기본 Profile을 제공한다는 전제로 정리

    작은 기반 계약을 유지하면서, 정착한 편집 문법을 기본 Profile의 구체적 약속으로 제공할 수 있다. 이번 조사에서 가장 중요한 보정은 예외를 찾는 작업과 기본값을 결정하는 작업을 함께 해야 한다는 점이다.

    사용자가 도중에 명확히 한 전제를 우선해 읽는다: Cmd+Z → Undo, 편집과 함께 선택 영역 복원은 기본으로 제공한다. 다양한 구현의 반례는 그 기본값의 범위와 변형을 설명한다.

    읽을거리 배울 내용
    학습 10: 사용자 전제와 Profile 유연한 기반과 믿을 수 있는 default를 함께 제공한다는 목표
    학습 11: 기본값의 실제 구현 근거 Undo와 선택 복원을 기본 계약으로 구체화할 근거, 기존 owner와의 연결
    학습 6: 명령을 보낸 곳과 받을 곳 Toolbar·focus·명령 대상·실행 가능 여부의 구별
    학습 7: 미적용·거절·이벤트 차단 정상적인 후보 탐색과 잘못된 대상 전이를 구별하는 기준
    학습 8: History의 범위 수신처·기록 범위·작업 묶음·선택 복원이 서로 다른 결정인 이유
    학습 9: Clipboard 표현과 수신 해석 여러 표현을 통한 교환과 Paste 정책의 경계
    학습 12: Cut 실패의 관찰 범위 callback 테스트와 후속 native 동작 검증의 차이
    학습 13: IME와 기본 편집 의미 입력 중 표시·문서 확정·Undo step의 구별, 표준 이슈의 마지막 댓글까지 읽는 방법

    하이라키에 대한 결론

    현재 문서의 대상별 계약 + 입력 계약 → 함께 검증하는 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이 약속할 결과를 적고 아래 조합에서 입증하는 데 둘 수 있다.

    1. 셀 내부 편집과 바깥 구조 편집: 진입·복귀·Copy 대상·거절 이후 경로.
    2. 같은 문서의 여러 view: Undo 수신 History와 복원할 selection의 귀속.
    3. 서로 다른 편집기 사이 Paste: 표현 선택·변환·손실·거절의 기준.
    4. 실제 native 입력: Cut 실패 이후 동작, IME 완료·취소·Undo·focus 이동.

    편집 Undo 시 선택을 복원하는 기본 계약과, 선택 이동 자체를 독립 Undo step으로 기록하는 정책은 계속 구별한다. 기본 Profile에서 허용할 설정과 다른 Profile로 식별할 차이도 사례별로 명시해야 한다.

    이번 라운드의 결과 범위

    학습 댓글 8개에 공식 자료·로컬 근거·반례·읽을 질문을 연결했다. 연결한 외부 URL 22개를 열어 확인했고, 잘못된 APG 절 anchor 1개를 실제 anchor로 바로잡았다. 본문 안의 고정 commit 소스 링크 9개도 파일과 줄 위치를 확인했다. 링크 검사는 자료 접근성과 위치 확인이며 외부 구현의 적합성 인증은 아니다.

    런타임·공개 API·테스트·package·설계 파일은 변경하지 않았다. #726은 c8570dc7 그대로 열려 있으며 머지하지 않았다. 기존 테스트는 내용을 읽어 대조했고, 이번 라운드에 테스트 재실행이나 실제 브라우저/OS IME 검증은 수행하지 않았다. 이슈는 후속 설계와 검증을 위해 열어 둔다.

  19. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    기본 Profile 설계 반영 — 조사 결과를 기존 초안과 PR에 연결

    사용자가 “Core는 유연하게 다 가능하게 가져가되 default를 제공”, “Cmd+Z가 Undo”, “선택했던 영역도 Undo에 포함”이라는 전제를 확인하고 이어서 “계속해”라고 요청했다. 학습 10의 전제를 기존 설계 초안에 반영한다.

    Goal Anchor — 원래 범위 유지

    • Outcome: 앱 사례와 정착한 편집 관습에서 장기간 호환성을 지킬 최소 개념·공통 불변 조건·profile별 차이·책임 하이라키를 도출한 설계 초안을 만든다.
    • Done: 사례와 근거를 기본 계약·profile 선택·기존 owner·적합성 사례로 연결하고, 검증된 부분과 아직 실행하지 않은 조합을 구별한다. 판단 근거와 검증 결과를 이슈에 남기고 문서 PR로 제공한다.
    • Don't: runtime·공개 API·Stable profile·package 배치를 변경하지 않는다. 새 editor·command bus·profile registry를 도입하지 않는다. 표준 완성이나 독립 구현 간 상호운용 인증으로 주장하지 않는다.

    이번 구체화는 다음 의미를 보존한다.

    • 기본 Profile은 정착한 기본 동작을 실제 계약으로 제공한다. 예외의 존재만으로 기본값 결정을 미루지 않는다.
    • 편집 Undo 시 내용과 선택을 함께 복원한다. 선택 이동 자체를 독립 Undo step으로 기록할지는 별도 정책이다.
    • 대상별 계약과 입력 계약을 함께 검증하는 Hands profile 구조를 유지한다. Core와 기존 정본 모듈의 책임을 Profile 구현으로 복제하지 않는다.
    • 같은 Profile에서 허용할 설정과 다른 Profile/revision으로 식별할 차이, 기본값 변경의 호환성 경계를 설명한다. 새 public type이나 설정 API를 확정하지 않는다.
    standards/editing-grammar.md
    ├─ 기본 Profile의 역할·기본 동작·허용할 차이
    ├─ Undo/selection의 구체적인 시작 상태와 기대 결과
    ├─ 중첩·History 귀속·교환·native 입력의 검증 경계
    └─ 기존 owner에서 후속 코드 변경을 설계할 위치와 순서
              |
              +-- 문서 검사·링크·전체 diff 검토
              +-- 기존 #726 갱신·검증 결과 기록
    

    현재 #725와 #726이 이 설계 작업을 소유하고 있다. 원래 작업 디렉터리의 변경은 보존하고 기존 작업 브랜치 issue-725-editing-grammar-derivation에서 진행한다. 문서 검사는 docs:evaluate, Markdown 링크/렌더링, 기존 EG 규칙·owner 보존과 범위 대조로 한다. 추가 API나 실제 입력 동작의 구현·머지는 이번 작업에 포함하지 않는다.

  20. developer-1px commented on Sep 7, 2026

    @developer-1px
    OwnerAuthor

    학습 14 — 단축키에서 근육기억으로 정착한 편집 문법을 찾기

    사용자가 조사 기준을 보완했다. “단축키가 만들어진다는 것은 변하지 않을 중요한 관습”, “근육기억 때문에 한번 정하면 되돌리기 어렵다”, 따라서 핵심 기능을 찾을 때 “단축키를 제공하는 기능부터” 살펴보자는 힌트다. 이를 기존 #725의 공통 문법을 도출하는 방법에 반영한다. 원래 Goal Anchor와 문서 변경 범위는 유지한다.

    채택하는 조사 방법

    단축키는 반복해서 실행하도록 제품이 드러낸 기능을 찾는 출발점이다. 특히 여러 제품과 오랜 자료에서 반복되는 기능부터 대상·결과·선택·복원을 비교한다. 단축키가 있다는 사실만으로 모든 기능을 Core로 승격시키거나 영구 표준으로 인증하지 않는다.

    단축키로 노출된 작업
        |
        v
    어느 맥락에서 무엇을 대상으로 어떤 결과를 만드는가?
        |
        +-- 여러 대상에서 유지되는 의미 → 공통 문법 후보
        +-- 셀·텍스트·객체마다 달라지는 의미 → 대상별 계약
        +-- 플랫폼·모드별 키와 입력 수신 → 입력 계약
        +-- 저장·인쇄 등 외부 효과 → Application 계약
                    |
                    v
    기본 Hands profile이 조합하고 익숙한 기본 동작을 약속
    

    이 도식은 조사 결과를 분류하는 방법이다. 새로운 command bus나 runtime 계층 설계가 아니다.

    공식 자료로 비교해 볼 예

    단서 확인한 관습 도출할 질문
    Undo Apple의 Cmd+Z, Excel의 Ctrl+Z 같은 복원 의도가 어느 History와 선택을 되돌리는가?
    Shift+Arrow Apple의 텍스트 범위 확장, Excel의 셀 범위 확장 확장의 의미를 공유하면서 문자·셀의 단위와 topology는 어디서 정하는가?
    F2·Escape Excel은 셀 편집 진입과 입력 취소를 설명하고, APG Grid는 셀 탐색과 내부 조작을 구별한다 진입 전 선택, 진행 중 draft, 확정·취소 후 복귀 대상을 어떻게 약속할 것인가?
    Save Apple과 Excel에 저장 단축키가 있음 반복되는 중요한 관습이어도 외부 저장 책임은 왜 문서 편집 Core와 다른가?

    현재 제품 문서는 현재 공개 동작의 근거다. 같은 의미가 얼마나 오래 유지됐는지는 기존에 읽은 1992년 HIG·Windows Edit 메뉴 지침 등과 대조해야 한다. 현재 단축키 표만으로 30년의 연속성을 증명했다고 표시하지 않는다.

    기본값 호환성에 주는 의미

    설계 판단은 근육기억으로 익힌 조작도 호환성의 대상이라는 것이다. 기본 Cmd+Z를 유지하더라도 다른 History에 전달하거나 편집 전 선택을 복원하지 않게 바꾸면 사용자가 익힌 작업은 달라진다. 반대로 사용자가 Profile이 허용한 설정으로 키를 바꾸는 것은 기본값을 몰래 바꾸는 일과 구별한다.

    따라서 설정 생략 + 편집 맥락 + 입력 → 대상·결과·후속 선택·History를 함께 검증하도록 문서의 기본 Profile 절에 연결한다. 단축키에 직접 드러나지 않는 선택 mapping·원자성·gesture 취소도 발견된 작업이 성립하는 데 필요하면 기반 계약에 남는다.

    현재 변경은 standards/editing-grammar.md의 조사 방법과 기본값 계약을 보완한다. runtime·공개 API·Stable profile을 변경하거나 아직 실행하지 않은 입력 사례를 통과로 표시하지 않는다.

  21. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    학습 15 — 유연한 기반 위에서 기본 Profile의 약속을 구체화한 결과

    PR #726을 갱신했다. 커밋 412f5121은 standards/editing-grammar.md 하나만 변경한다. 기존 EG 규칙 9개와 canonical owner 표는 main 대비 그대로 유지했다.

    이제 문서에서 결정한 것

    기반 계약
      각 owner의 보장과 확장 가능성
           |
           v
    대상별 계약 + 입력 관습 + 선택한 History 계약
           |
           v
    기본 Hands profile
      설정 생략 시 익숙한 동작을 약속
      Undo는 편집 전 내용·선택을 함께 복원
      허용한 설정과 다른 Profile/revision을 구별
    

    여기서 유연성은 가능한 정책을 지원하는 능력이고, 기본값은 그중 무엇을 실제로 약속하는가의 결정이다. 기반 API가 여러 동작을 표현할 수 있어도 같은 Profile의 기본 동작을 임의로 바꿔도 된다는 결론은 나오지 않는다. 사용자의 설정 생략도 유효한 사용이므로 호환성 검증에 포함한다.

    사용자가 추가한 단축키 힌트도 같은 결론으로 연결했다. 기본 키를 유지하더라도 수신 History나 선택 복원을 바꾸면 근육기억으로 익힌 작업이 달라진다. 학습 14에 단축키에서 문법 후보를 추출하는 방법과 공식 읽을 거리를 따로 남겼다.

    Undo의 약속을 검토 가능한 사례로 바꾸기

    Rich Text의 한 text node에서 Alpha의 ph를 선택하고 X로 바꾼다고 하자. 외부 변경은 없고 시작 History는 비어 있다.

    단계 내용 기대하는 선택·History
    시작 Alpha anchor 2 → focus 4 또는 반대 방향으로 ph 선택
    교체 AlXa offset 3의 caret, Undo 가능
    Undo Alpha 시작의 범위와 방향 복원, Redo 가능
    Redo AlXa offset 3의 caret 복원, Undo 가능

    Undo 다음에 선택만 옮기는 경우도 별도로 적었다. 기본 Profile에서는 그 이동이 새 문서 History entry를 만들거나 Redo를 지우지 않으며, Redo는 기록된 편집 후 선택을 복원해야 한다. 이는 편집과 함께 선택을 복원하는 정책과 선택 이동 자체를 Undo 기록에 넣는 정책을 구별한다.

    이 표는 새로 구체화한 기대 결과이며 새 테스트 통과를 주장하지 않는다. 기존 model selection 증거와 실제 native range 복원 증거도 분리했다. API·binding을 바꿀 필요가 있는지는 기존 Web·Affordance·Editing·domain API로 이 사례를 연결할 때 확인하도록 설계 위치를 남겼다.

    검증과 남은 경계

    • 커밋 412f5121의 CI: Plan·Package·Site 통과, External kit은 계획에 따라 skipped
    • npm run docs:evaluate, git diff --check 통과.
    • 내부 링크 35개 참조 / 33개 대상 존재, GFM 표 16개의 열 구조·code block 5개·중복 없는 anchor 확인.
    • 잘못된 APG Grid anchor를 수정하고 Clipboard cut action anchor도 확인.
    • 원격 PR의 문서가 로컬 커밋과 일치하고, PR 본문·변경 파일·원래 #725의 설계 범위를 대조했다.
    • 중첩·Toolbar 대상·여러 view의 History·native Cut·IME 등 12개 조합 검증 질문은 미실행 후보로 유지한다. 이 문서 변경은 Stable admission이나 모든 Hands의 구현 완료를 뜻하지 않는다.

    원래 작업 디렉터리의 변경은 보존했다. 작업 브랜치는 issue-725-editing-grammar-derivation이며 PR은 열린 상태다. UI 변경이 없어 show-me는 해당하지 않는다.

  22. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    기본 동작별 계약표와 최소 코드 변경안 — 실행 계획

    사용자가 다음 단계를 물었고, 다음 산출물을 “기존 설계 문서 안의 기본 동작별 계약표와, 그 계약을 만족시키기 위한 최소 코드 변경안”으로 제안한 뒤 “해보자”라고 승인했다. 기존 #725 / #726에서 이 설계를 구체화한다.

    Goal Anchor — 기존 설계 목표 유지

    • Outcome: 앱·편집 사례와 정착한 편집 관습에서 장기간 호환성을 지킬 최소 개념·공통 불변 조건·profile별 차이·책임 하이라키를 도출한다.
    • Done: 단축키에서 추린 기본 동작을 대상 → 결과 → 후속 선택 → Undo 단위로 비교하고, 공통 보장·대상별 의미·입력 해석·기본 Profile의 약속을 기존 owner에 연결한다. 선택 → 교체 → Undo → Redo를 기존 공개 API로 확인해, 코드 변경이 필요한 지점과 검증만 필요한 지점을 구별한 변경안을 문서 PR로 제공한다.
    • Don't: runtime·공개 API·Stable profile·package 배치를 변경하지 않는다. 새 범용 editor·command bus·profile registry를 도입하지 않는다. 새 설계와 제한된 실행 확인을 모든 Hands의 완성이나 독립 구현 간 상호운용 인증으로 주장하지 않는다.

    보존할 합의

    • 먼저 다룰 동작: 탐색·선택·선택 확장·전체 선택 / 삽입·교체·삭제 / Copy·Cut·Paste / Undo·Redo / 내부 편집 진입·확정·취소·복귀.
    • 이미 조사한 Text·Tree·Sheet·Object 등 앱 사례를 같은 관찰 항목으로 비교한다. 단축키는 후보를 찾는 단서이며 모든 기능의 Core 승격 기준은 아니다.
    • 공통 보장은 기존 기반 모듈, 대상별 의미는 해당 editor, 입력 해석은 adapter·Affordance에 연결한다. 기본 Profile은 그 조합의 익숙한 기본 동작을 약속한다.
    • Host에서 편집 의미를 직접 구현하는 연결이 발견되면 정본 API의 지원 여부를 확인하고 변경안에 기록한다. 이번에는 그 runtime을 수정하지 않는다.
    • 첫 실행 확인은 편집 전후 내용·선택 방향·Undo/Redo 기록이다. 기존 공개 API로 성립하는 계약에는 새로운 API를 제안하지 않는다.
    기존 자료·코드
    ├─ 기본 동작의 범위와 계약표
    ├─ 대상별 결과·선택·History 비교
    ├─ 공개 API로 선택 → 교체 → Undo → Redo 확인
    └─ 책임 경계와 최소 변경안
        └─ 문서 검사·diff 검토·기존 PR 갱신
    

    검증은 기존 관련 테스트와 필요한 공개 API 실행 확인, docs:evaluate, Markdown 링크·렌더링, EG 규칙·owner 보존으로 한다. 임시 실행 확인과 영구 conformance vector, native browser/OS 입력의 증거를 구별해 남긴다. 원래 작업 디렉터리의 변경을 보존하고 기존 issue-725-editing-grammar-derivation 브랜치를 사용한다.

  23. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    학습 16 — 계약표를 공개 API에 대입해 보니 Core보다 조합 경계가 남았다

    선택 → 교체 → Undo → Redo부터 실제 공개 API로 확인했다. 저장소의 현재 source를 빌드한 뒤 package entrypoint를 사용했으며 runtime 코드는 수정하지 않았다.

    확인된 동작

    • Alpha의 ph를 X로 교체하면 AlXa와 offset 3의 caret이 된다.
    • Undo는 Alpha와 편집 전 선택 범위·방향을 복원한다.
    • Undo 후 caret만 옮겨도 Redo 기록은 유지되고, Redo는 AlXa와 편집 후 caret을 복원한다.
    • 선택 방향 2 × Undo 후 이동 여부 2 × 직접 호출·기본 metaKey 해석·기본 ctrlKey 해석 3 = 12개 실행이 모두 기대와 일치했다.

    키 입력 확인은 createWebKeyboardAdapter().resolve가 만든 의도를 editor의 공개 undo·redo에 전달한 범위다. DOM 수신·OS IME·native selection 복원까지 통과했다고 해석하지 않는다. 이번 임시 실행을 영구 conformance suite의 테스트 개수에 더하지도 않는다.

    이 증거 때문에 해당 경로에는 Core나 History API의 확장이 필요하다고 제안하지 않는다. 다음 구현에서는 같은 사례를 기존 owner의 conformance binding에 정착시키고 실제 입력 경로와 연결하면 된다.

    기본 계약과 현재 API 사이의 공백

    기본 Profile에서 채택한 결과 현재 확인한 결과 최소 변경의 위치
    같은 맥락의 전체 선택을 반복하면 유지 selectAllAffordance(..., { allSelected: true })는 clear 반환 Affordance에서 반복 입력 정책을 명시적으로 선택. 기존 토글 호출의 생략된 설정은 보존
    유효한 대상의 draft가 검증 거절되면 내용을 고쳐 재시도할 수 있음 Order editor는 거절하고 내용·선택·History를 보존하지만 createRenameSession은 draft를 지우고 onFinish 호출 성공 여부를 받는 Affordance 확정 경로 추가. 기존 void callback은 별도 호환 경로로 보존
    한 전체 선택의 결과를 한 전이로 관찰 Document·Order·Tree·Sheet의 선택 API는 단일 point의 replace/extend/toggle을 받음 해당 domain에서 기존 Selection family의 결과를 한 번에 적용하는 공개 경로 설계. Host의 첫·끝 연속 dispatch로 대체하지 않음
    같은 입력 계약의 Undo는 같은 키 해석을 사용 구조 입력은 Web resolver를 소비하지만 Rich Text Web은 별도 키 조건을 검사 공통 Undo 해석은 Web resolver를 소비. Rich Text의 native lifecycle과 특수 삭제는 기존 owner에 유지

    마지막 행은 source 비교다. 예를 들어 Web 기본 resolver는 Alt+Mod+Z를 해석하지 않지만 Rich Text Web의 현재 Undo 조건은 altKey를 검사하지 않는다. 공통 resolver로 연결할 때 기존 수용 범위를 몰래 바꾸지 않도록 입력 정책·호환성 사례를 먼저 명시해야 한다.

    여기서 draft 유지와 반복 전체 선택 유지는 이 초안에서 채택한 기본 Profile의 결정이다. 기존 API가 이미 약속한 규칙을 위반했다는 판정과 구별한다. 특히 rename의 현재 callback은 void 계약이어서, 반환한 편집 결과를 해석하리라고 기대할 근거가 없다.

    하이라키에 대한 결론

    Core                         변경 필요 없음 — 이번 공개 API 사례 기준
    Selection·Editing History    기존 전이·기록·복원 활용
    대상별 editor                전체 선택을 한 번에 적용하는 연결 보완
    Web·Affordance               기본 입력 정책·확정 결과의 연결 보완
    기본 Hands profile           어떤 조합과 기본값을 약속하는지 명시
    Host                         정본 API의 조합 유지
    

    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를 해석하도록 루트를 실행 위치로 둔다.

    import assert from 'node:assert/strict';
    import { createJSONDocument } from '@interactive-os/json-document';
    import { createRichTextEditor } from '@interactive-os/json-document-rich-text';
    import { createWebKeyboardAdapter } from '@interactive-os/json-document-web';
    
    const initial = {
      profile: 'urn:interactive-os:json-document:rich-text:1', id: 'doc', type: 'doc',
      content: [{ id: 'p', type: 'paragraph', content: [{ id: 't', type: 'text', text: 'Alpha', marks: [] }] }],
    };
    const point = offset => ({ kind: 'text', nodeId: 't', offset, affinity: 'forward' });
    const range = (anchor, focus = anchor) => ({ kind: 'range', ranges: [{ anchor: point(anchor), focus: point(focus) }], primaryIndex: 0 });
    const changed = { ...initial, content: [{ ...initial.content[0], content: [{ ...initial.content[0].content[0], text: 'AlXa' }] }] };
    const keyboard = createWebKeyboardAdapter();
    const observations = [];
    function expectState(editor, value, selection, canUndo, canRedo) {
      assert.deepEqual(editor.snapshot.value, value);
      assert.deepEqual(editor.snapshot.selection, selection);
      assert.equal(editor.snapshot.canUndo, canUndo);
      assert.equal(editor.snapshot.canRedo, canRedo);
    }
    for (const [anchor, focus] of [[2, 4], [4, 2]]) {
      for (const moveAfterUndo of [false, true]) {
        for (const input of ['headless', 'metaKey', 'ctrlKey']) {
          const document = createJSONDocument(structuredClone(initial));
          const editor = createRichTextEditor({ document });
          assert.equal(editor.dispatch({ type: 'selection.set', selection: range(anchor, focus) }).ok, true);
          expectState(editor, initial, range(anchor, focus), false, false);
          assert.equal(editor.dispatch({ type: 'text.insert', text: 'X' }).ok, true);
          expectState(editor, changed, range(3), true, false);
          const invoke = type => {
            if (input === 'headless') return editor[type]();
            const command = keyboard.resolve({ key: 'z', shiftKey: type === 'redo', metaKey: input === 'metaKey', ctrlKey: input === 'ctrlKey' });
            assert.deepEqual(command, { type });
            return editor[command.type]();
          };
          assert.equal(invoke('undo').ok, true);
          expectState(editor, initial, range(anchor, focus), false, true);
          if (moveAfterUndo) {
            assert.equal(editor.dispatch({ type: 'selection.set', selection: range(0) }).ok, true);
            expectState(editor, initial, range(0), false, true);
          }
          assert.equal(invoke('redo').ok, true);
          expectState(editor, changed, range(3), true, false);
          observations.push({ direction: anchor < focus ? 'forward' : 'backward', moveAfterUndo, input, result: 'passed' });
        }
      }
    }
    console.log(JSON.stringify({ publicApiCases: observations.length, observations, scope: 'model and default keymap only; no DOM/native routing' }, null, 2));

    다음 코드는 제안한 기본 계약의 통과 테스트가 아니라 현재 정책과 거절 결과를 재현하는 코드다. label.rejected는 검증 실패를 만들기 위한 fixture 규칙이다.

    import assert from 'node:assert/strict';
    import { createJSONDocument } from '@interactive-os/json-document';
    import { createOrderEditor } from '@interactive-os/json-document-editing';
    import { createRenameSession, selectAllAffordance } from '@interactive-os/json-document-affordance';
    import { createWebKeyboardAdapter } from '@interactive-os/json-document-web';
    const stroke = { key: 'a', metaKey: true, ctrlKey: false };
    assert.deepEqual(selectAllAffordance(stroke, { allSelected: true }).hand, { type: 'clear' });
    const initial = { items: [{ id: 'a', label: 'Alpha' }] };
    const document = createJSONDocument(initial, {
      validate: value => value.items[0].label === 'Rejected'
        ? { ok: false, code: 'label.rejected', reason: 'Fixture rejects this label' }
        : { ok: true },
    });
    const editor = createOrderEditor(document);
    const before = structuredClone(editor.snapshot);
    let result;
    let finished = false;
    const rename = createRenameSession({
      onCommit: (itemId, label) => result = editor.dispatch({ type: 'item.rename', itemId, label }),
      onFinish: () => { finished = true; },
    });
    rename.begin('a', 'Alpha');
    rename.update('Rejected');
    assert.equal(rename.handleKey('Enter'), true);
    assert.equal(result.ok, false);
    assert.deepEqual(editor.snapshot.value, before.value);
    assert.deepEqual(editor.snapshot.selection, before.selection);
    assert.equal(editor.snapshot.canUndo, false);
    assert.equal(rename.getSnapshot(), null);
    assert.equal(finished, true);
    const keymap = createWebKeyboardAdapter();
    const altUndo = keymap.resolve({ key: 'z', shiftKey: false, metaKey: true, ctrlKey: false, altKey: true });
    assert.equal(altUndo, null);
    console.log(JSON.stringify({
      repeatSelectAll: 'clear',
      rejectedRename: { result, valuePreserved: true, selectionPreserved: true, canUndo: false, draft: rename.getSnapshot(), onFinishCalled: finished },
      webDefaultAltModZ: altUndo,
      interpretation: 'Current API observations; the proposed default Profile is not yet implemented for repeat Select All or retained rejected drafts',
    }, null, 2));

    기존 테스트 실행:

    npm run test:projects -- --project json-document-editing --project json-document-rich-text --project json-document-selection --project json-document-affordance --project json-document-web conformance/editing-grammar.test.ts conformance/select-all.test.ts session-history.test.ts tree-editor.test.ts object-editor.test.ts sheet-editor.test.ts affordance.test.ts web-adapters.test.ts
  24. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    기본 계약표·최소 코드 변경안 완료

    PR #726의 커밋 97405f78에 반영했다. standards/editing-grammar.md 안에서 기존 표를 확장·정리했으며 변경 파일은 하나다.

    산출물

    • 기본 동작 12개 계약표: 대상 → 결과 → 후속 선택 → Undo 단위와 profile별 차이·owner를 연결했다. 반복 전체 선택 유지, 유효한 대상의 draft 확정 거절 시 유지라는 기본 결정도 명시했다.
    • 대상별 결과 비교: Rich Text·Document·Tree·Sheet·Object의 Copy 대상, 교체·제거, Paste와 후속 선택을 같은 표에 정리했다. Order rename과 나머지 앱의 고유 의미는 기존 사례와 연결했다.
    • 하이라키 검토: 확인한 Undo 경로는 현재 Core·Selection·History로 성립한다. 공통 의미를 지키면서 입력·대상별 차이를 기존 owner에서 구체화하는 배치를 유지한다.
    • 최소 코드 변경안: 전체 선택의 반복 정책과 domain의 한 번에 전체 선택하기, 성공 여부를 받는 draft 확정, Web resolver를 소비하는 Undo 입력 해석으로 좁혔다. 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 증거는 후속 구현 단계의 검증 항목으로 남긴다.

  25. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    승인된 후속 구현으로 연결

    사용자가 기본 계약표와 최소 코드 변경안을 전달받고 “진행해”라고 요청했다. 네 구현과 영구 회귀 검증은 #727에서 진행한다. #725와 #726의 문서 설계 범위는 유지하며 기존 원문·판단 기록을 변경하지 않는다. 구현은 최신 main 기반의 별도 PR로 제공한다.

  26. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    프로토콜 건강도 감사 — 책임의 중복, 행동 범위, 최소성

    판정: Core의 여섯 멤버는 책임이 비교적 선명하다. 그러나 전체 편집 프로토콜을 ‘필요한 행동을 모두 제공하며, MECE하고 최소화되었다’고 판정할 수는 없다. 같은 책임의 재구현이 있고, 일부는 실제 동작 불일치로 이어진다.

    이번에는 코드를 수정하지 않았다. 아래는 설계 판단과 후속 수정의 근거다.

    감사 기준과 범위

    • 구현 기준: #730의 ba1f0ee. 감사 시점에 #730은 OPEN이다. main에 모두 반영된 상태라는 뜻이 아니다.
    • 설계 기준: #726의 standards/editing-grammar.md. 설계 초안과 실행 증거를 분리했다.
    • 29개 라이브러리 workspace의 진입점·의존 관계를 조사하고, Document·Order·Sheet·Object·Tree·Database·Kanban·Calendar·Annotation·Rich Text의 10개 editor와 Composer 조합을 추적했다.
    • 집중 범위: Core 계약, Selection, EditingSession/History, Clipboard, 단축키, Gesture, 관련 Web/React/Host 경계.
    • UI 라이브러리 전체 내부, 모든 Calendar 조건, 모든 OS/browser/IME 조합, 모든 외부 소비자는 전수 검증하지 않았다. 공개 export 전체의 완전한 적합성 인증도 아니다.
    • 소스 분석에 더해 기존 빌드의 공개 API로 JSON 값 수용, 단축키 해석, Rich Text의 React SSR 경로를 실행했다. 이번 감사에서 전체 테스트 스위트를 다시 실행하지는 않았다.

    현재 공통화의 실제 범위

    항목 확인 결과 의미
    EditingSession editor 10/10이 공통 구현 사용 문서 변경과 선택·History를 묶는 책임은 상당히 모였다
    Selection 9/10이 canonical family를 직접 또는 wrapper로 사용 Annotation이 별도 선택 전이를 구현한다
    구조화된 Cut 제공하는 7/7이 cutEditingClipboard 사용 이 책임의 정본 소비는 좋은 상태다
    공통 editingGrammar(...) suite 3/10: Document, Sheet, Rich Text 나머지 7개에 개별 테스트가 없다는 뜻은 아니다. 같은 규칙의 공통 적합성 연결이 부족하다
    행동 범위 Database는 Copy/Paste가 있으나 Cut이 없다. Kanban·Annotation editor에는 Copy/Cut/Paste가 없다 지원하지 않는 정책인지 아직 구현하지 않은 것인지 profile별 계약으로 구분해야 한다

    Core의 JSONDocument는 value / at / query / validatePatch / commit / subscribe로 구성된다. 현재 조사에서 이 여섯 책임 중 하나를 없애야 한다는 근거는 찾지 못했다. 단일 주소 읽기와 질의, 변경 검증과 실행, 현재 값과 변경 관찰은 서로 다른 요청이다. 다만 멤버가 여섯 개라는 사실 자체가 내부 구현의 중복 부재를 보장하지는 않는다.

    1. 주소 해석을 재구현하여, 같은 editor를 다른 소비자가 읽지 못한다 — 우선 수정

    정본은 Core의 Pointer 모듈이다.

    Rich Text editor는 document.at(pointer)를 사용한다. 반면 React의 documentAtPointer는 slice/split/replaceAll로 주소를 직접 해석한다.

    공개 createRichTextEditor와 RichTextEditorSurface, React renderToString으로 재현했다.

    pointer editor 생성 React 렌더
    /editor 성공 성공
    #/editor 성공 실패: Rich Text document was not found at "#/editor".

    DOM이나 로그인 상태가 필요한 재현이 아니다. editor가 받아들인 주소를 그 editor의 공식 React 소비자가 받아들이지 못한다.

    또한 토큰 인코딩은 canonical 구현 외에 다음 세 곳에서 같은 ~0 / ~1 규칙을 구현한다.

    분류: 중복 구현. 인코딩은 이미 있는 buildPointer를 소비할 수 있다. React의 snapshot 읽기는 canonical 주소 해석을 사용하면서 snapshot의 참조 동일성과 성능을 보존하는 연결 방법을 정해야 한다. Core port의 멤버를 늘리는 것이 자동으로 필요한 것은 아니다.

    완료 조건: 동일한 지원 주소 집합에 대해 Core → Rich Text → React가 같은 대상을 읽고, token 인코딩의 독립 구현이 남지 않는다.

    2. ‘JSON 값으로 유효하다’의 정의가 계층마다 다르다 — 우선 수정

    정본 Core의 JSON 검증·복제는 유한한 숫자, 배열의 실제 원소, 허용 객체 형태 등을 검사한다.

    Editing의 isClipboardJSONValue는 이 책임을 별도로 구현한다. Sheet·Database clipboard parser가 함께 사용한다. Rich Text isJSONValue에도 일반 JSON 값 판별이 따로 있다.

    공개 API 실행 결과:

    셀 값 Core applyPatch Sheet parser Database parser
    NaN not_serializable 수용 수용
    Infinity not_serializable 수용 수용
    new Date(0) not_serializable 수용 수용
    Array(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 해석이 있다.

    입력 Web 기본 resolver 다른 경로
    Ctrl+Alt+Z 명령 없음 Composer: history.undo
    Ctrl+Backspace 명령 없음 deleteAffordance: delete
    Ctrl+Alt+Shift+A 명령 없음 selectAllAffordance: 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. 드래그 수명주기에 상태 소유자가 겹친다 — 통합 설계 후보

    분류: Web session의 책임 배치 문제, Board의 공통 수명주기 중복 후보. 실제 상태 불일치까지 재현한 항목은 아니다. target이 없을 때 commit하지 않는 Board 정책 등은 유지해야 한다.

    반대로 createCanvasGestureSession은 이미 정본에 위임하는 wrapper다. Pointer capture/release를 관리하는 Web pointer session도 별도 책임이므로 같은 이름이라는 이유로 합치면 안 된다.

    6. 공개된 개념의 소유권과 필요성도 줄일 여지가 있다

    Selection의 core/session.ts에 다음 계약이 공개되어 있다.

    • SelectionSession
    • ScopedSelection
    • SelectionEditIntent
    • SelectionEditResult
    • SelectionHistoryEntry

    앞의 네 가지는 레포 내 production 소비를 찾지 못했다. 마지막 SelectionHistoryEntry는 실제 EditingSession이 사용한다.

    분류: 앞의 네 가지는 필요성 미확인·축소 후보, History 계약은 소유권 검토 대상. 레포 내 소비가 없다는 사실만으로 외부 사용도 없다고 결론 내리거나 바로 삭제하면 안 된다. 실제 작업 경계와 History를 Editing이 소유하는 현재 구조에 맞게, Selection의 공개 계약이 무엇을 약속하는지 먼저 좁혀야 한다.

    개념을 한 번 공개하면 기능 구현보다 오래 유지해야 할 수 있다. 사용 사례와 독립적인 불변 조건을 제시하지 못한 개념을 미리 동결하는 것은 최소성에 불리하다.

    후보 판정 장부와 유지할 차이

    책임·출현군 분류 판단
    10개 editor → EditingSession canonical 소비 유지
    Selection family 소비 9개 / Annotation 자체 전이 canonical 소비 / 중복 구현 Annotation 정리
    Cut 제공 editor 7개 canonical 소비 유지
    Pointer encoder 1 정본 + 3 별도 구현, React 직접 해석 중복 구현 기존 owner 소비
    A2UI Host의 직접 경로 해석 Host에 배치된 재사용 책임 A2UI 상대 경로 의미와 Pointer 변환의 경계를 먼저 확인; 동일 의미라고 단정하지 않음
    JSON 기본 유효성 검사 중복 구현·API 공백 공통 JSON 제약과 도메인 schema 분리
    기본 단축키 해석 중복 구현·정책 공백 기본 resolver와 profile 선택으로 정리
    Annotation preview의 도메인 계산 API 공백 도메인 연산을 공유
    Gesture / Board / Web DnD 일부 중복 후보·배치 문제 공통 수명주기와 target/플랫폼 사실 구분
    Canvas Gesture wrapper canonical 소비 별도 runtime 중복 아님
    로컬/협업 contenteditable의 isCompositionInput 중복 플랫폼 판별 Web owner의 공통 판별 후보
    로컬/협업 History 및 편집 완료 전략 서로 다른 의미 책임 로컬 inverse와 협업 인과관계 복원은 유지
    Key / Range / Materialized Range / Mask 서로 다른 대상 표현 하나의 만능 Selection으로 합치지 않음; Mask는 완성된 raster editor의 증거가 아님
    Core의 독립 참조 구현 적합성 검증 역할 production 중복으로 취급하지 않음
    사용 근거가 없는 Selection 공개 계약 4개 미확인 소비 조사와 호환성 판단 후 축소 여부 결정

    하이라키를 판단하는 기준

    다음을 하나의 평면적인 기능 목록으로 분류하면 다시 겹친다. 대상의 종류, 작업의 수명주기, 입력 플랫폼, 기본 정책은 서로 다른 축이다.

    책임의 정본
    ├─ Core        JSON 값 · 주소 · 원자적 변경 · 관찰
    ├─ Selection   대상 집합/범위 · 선택 전이 · 재조정
    ├─ Editing     작업 경계 · 문서와 선택의 결과 · History
    ├─ Domain      Text/Sheet/Object/...의 유효한 연산과 제약
    ├─ Affordance  입력 방식에 독립적인 조작의 진행 상태
    ├─ Web         플랫폼 이벤트 해석 · DOM/clipboard/capture 연결
    ├─ Connector   framework/외부 시스템과 정본 API 연결
    └─ Host        조합 · 제품 정책 값 · 배치 · 외부 인스턴스 주입
    
    Profile = 이 책임들을 가로지르는 지원 범위 + 기본값 + 적합성 조건
    

    이는 새로운 패키지 목록이나 일렬의 의존 계층을 추가하자는 제안이 아니다. 같은 규칙을 어디서 구현해야 하는지 판단하는 책임 지도다. Profile도 새로운 command bus나 상태 저장 runtime일 필요가 없다.

    ‘할 수 있다’는 최소한 세 가지를 구분해야 한다.

    1. JSON Patch와 확장 지점으로 표현할 수 있다.
    2. 공식 editor가 해당 행동을 제공한다.
    3. 선택 복원·실패 시 불변·정확히 한 번의 History 등을 기본 동작으로 보장한다.

    현재는 1에서 2, 2에서 3으로 넘어가는 연결이 일부 비어 있다. 따라서 기능을 모두 Core에 가져오는 것으로 해결되지 않는다.

    권장 실행 순서

    1. 재현된 Pointer 소비 불일치와 JSON 값 검증 불일치를 고친다. 정본을 소비하는 계약을 먼저 증명한다.
    2. 단축키의 공통 해석, Annotation Selection/preview 소유권을 정리한다.
    3. 각 editor의 기본 행동표를 만들고 ‘지원 / 의도적 미지원 / 미구현’을 명시한다. 공통 editing grammar의 적용 가능한 규칙을 10개 editor에 연결한다.
    4. Gesture 수명주기와 사용 근거 없는 공개 계약을 축소 검토한다.
    5. 이 증거를 바탕으로 기본 Profile을 동결한다.

    공유 API를 바꾸는 후속 작업의 완료 조건에는 owner의 export, 자체 API reference, site Usage, source registration, 소비자 연결과 의미 검증을 함께 포함해야 한다.

    학습할 핵심은 같은 이름이 아니라 같은 입력·불변 조건·실패 의미·수명주기를 소유하는가다. 주소 해석은 같은 책임의 다른 구현이 실제 호환성 실패를 만든 사례다. 반대로 local/causal History는 이름이 같아도 제거하면 의미가 사라지는 차이다. 최소 프로토콜은 개념 수만 줄인 결과가 아니라, 필요한 차이는 표현하면서 공통 규칙의 소유자는 하나로 만든 결과여야 한다.

  27. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    건강도 감사의 첫 구현 단계를 #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 동결의 증거로 확대하지 않는다.

  28. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    건강도 감사의 다음 구현을 #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 소유권과 연결해서 진행해야 한다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentation

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions