사용자가 설계 개선 후 “진행해”로 실행을 승인했다. 아래는 승인한 설계 원문이다. 설계 문서의 Done은 설계 산출물의 기준이며, 이 실행은 그 적합성 설계를 기존 owner에서 구현하는 후속 단계다. 이름 변경이나 미지원 명령 추가는 포함하지 않는다.
승인한 설계와 결정 원문
편집 문법의 안정화 설계
상태: Design Draft. 기존 public API와 Stable profile의 의미는 유지한다.
이 문서는 공통 편집 규칙의 소유자, Hands별 해석, 적합성 증거를 설계한다.
아래 제안의 구현 완료나 외부 상호운용성을 주장하지 않는다.
목표와 범위
오랫동안 정착한 편집 문법을 구현과 제품이 바뀌어도 유지되는 계약으로 만든다.
작은 Core는 장기간 약속할 수 있는 의미만 소유한다. JSON Document의 여섯
member와 편집 문법의 크기는 서로 다른 문제다.
- Outcome: 같은 Hands profile을 소비하는 제품은 선택·편집·복사·복원에서 같은
관찰 가능한 의미를 얻는다.
- Done: 이 설계에서 공통 규칙과 profile 선택을 구분하고, 각 규칙의 기존 owner,
현재 구현과의 차이, 이를 판정할 적합성 사례를 연결한다.
- Don't: 이번 설계로 Core API를 늘리거나 기존 동작을 변경하지 않는다. 새로운
범용 editor, command bus, profile registry나 package hierarchy를 만들지 않는다.
구현 근거의 범위는 JSON Document, Selection, Editing, Affordance, Web과
Document·Sheet·Rich Text의 대표 편집 경로다. Object의 전체 선택과 Database의
cut 미지원은 profile 차이를 판정하는 사례로 포함한다. 모든 Hands의 완성도,
브라우저별 입력 일치, 협업 wire protocol의 수렴은 이 설계의 검증 결과가 아니다.
현재 문제와 원인
EditingSession은 value·selection·history를 함께 처리하고 Selection family는
대상의 전이를 공유한다. 그러나 EditingIntent의 공통 계약은 type: string과
dispatch 형태이며, 동사의 사전 조건과 결과는 editor별 코드와 문서에 있다.
Official Hands도 아직 호환성 약속을 확정하지 않은 후보다.
이 때문에 여러 editor가 같은 API 형태를 제공해도 같은 편집 문법을 따른다는
증거가 되지 않는다. selectAllAffordance의 전체 선택 토글처럼 특정 관습이
범용 기본값으로 보이고, selection.move처럼 문서 변경과 선택 변경이 이름에서
구별되지 않는 사례도 있다. 동작을 선언하는 규칙과 그 규칙을 검증하는 사례의
연결이 부족한 것이 원인이다.
세 종류의 계약과 기존 소유자
다음은 새 runtime 계층이 아니라 기존 책임들이 약속할 내용의 구분이다.
| 계약 |
고정할 의미 |
정본 소유자 |
| 공통 편집 규칙 |
선택 전이, 편집의 원자성, 복사와 History의 관계 |
Selection·Editing |
| Hands profile |
편집 대상, 범위 해석, 삭제·붙여넣기 결과, 지원 작업 |
Document Type과 해당 editor의 기존 owner를 조합한 Hands |
| 입력 매핑 |
키·포인터·IME를 어떤 편집 의도로 해석하는가 |
Adapter·Affordance와 framework Connector |
keyboard / pointer / IME ─ Adapter·Affordance ─┐
직접 호출하는 프로그램 ──────────────────────┤
↓
해당 editor의 편집 의도
+ Selection / Topology
↓
EditingPlan + selectionAfter
↓
EditingSession → JSONDocument.commit
↓
해당 편집의 snapshot / History
이는 대표적인 값 변경 흐름이다. Copy는 조회이며, 선택만 바꾸는 작업은 document
commit을 만들지 않고, Undo/Redo는 선택한 History owner를 실행한다. 순수 JSON
소비자에게 Editing이나 Hands 설치를 요구하지 않는다.
| 기존 owner |
계속 소유할 책임 |
다른 곳으로 넘기지 않을 결정 |
json-document |
JSON 값·주소·검증·원자적 Patch·변경 알림 |
selection, clipboard, undo step을 Core에 넣지 않음 |
json-document-selection |
key/range/mask family, transition·map·reconcile·targets |
DOM focus와 문서 mutation은 각각의 owner가 처리 |
json-document-editing |
EditingPlan, snapshot, transaction, local History, external History 연결 |
같은 transaction·History를 각 Hand에서 다시 구현하지 않음 |
| 기존 Document Type/editor 모듈 |
유효한 대상·문서 연산·projection, 의도를 plan으로 변환 |
Host가 붙여넣기·삭제의 의미를 다시 결정하지 않음 |
json-document-affordance |
선택·활성화·취소의 입력 의미, gesture lifecycle |
좌표·DOM capture는 Web에 연결 |
json-document-web 및 text Web Adapter |
platform event, clipboard 교환, native editing lifecycle |
semantic edit는 해당 editor API로 전달 |
| React 등 Connector |
framework subscription·render·focus lifecycle |
문서·선택·History의 별도 상태 소유자를 만들지 않음 |
Document Type은 책임 이름이며 이 표로 package 재배치를 승인하지 않는다. 현재
Document·Sheet 등은 Editing에, Rich Text는 자신의 package에 구현돼 있다.
Hands는 기존 공개 API들의 함께 검증된 조합이다. Host는 제품 데이터·권한·copy·
layout·concrete external instance와 조합을 소유한다.
공통으로 고정할 편집 규칙
아래 ID는 설계 요구사항이다. 실제 동결은 owner의 versioned 계약과 적합성
증거를 통해 이루어진다. DOM API 모양, JSON 저장 shape, 특정 키 조합은 이
규칙의 전제가 아니다.
| ID |
관찰 가능한 규칙 |
Owner |
| EG-SELECT |
선택만 바꾸는 작업은 document value와 문서 Undo/Redo 기록을 바꾸지 않는다. 범위 확장은 유효한 기존 anchor를 보존하고 focus를 이동한다. |
Selection·Editing |
| EG-TARGET |
navigation 위치, 선택된 대상, native text caret을 구별한다. 문서 안에서 대상이 이동했을 때 identity를 유지하는지와 삭제 후 선택의 도착점은 해당 profile이 정한다. |
Selection·해당 editor |
| EG-EDIT |
값 변경은 patch와 selectionAfter를 한 편집 결과로 발행한다. 실패한 의도는 자신의 partial mutation·selection·History entry를 남기지 않는다. |
Editing |
| EG-COPY |
Copy는 현재 profile의 선택 대상을 구조화된 payload와 교환 표현으로 읽으며 document·selection·History를 바꾸지 않는다. |
해당 editor |
| EG-CUT |
Cut은 복사할 대상을 확정한 뒤 그 대상에 대한 제거 plan을 실행한다. payload 확보 실패 시 제거하지 않는다. 제거 실패 시 문서는 유지되며 성공한 cut으로 보고하지 않는다. |
Editing·해당 editor·Web |
| EG-PASTE |
Paste는 profile이 정한 위치·대체 범위·identity 규칙으로 한 편집을 실행하고 결과 Selection을 함께 정한다. 호환되지 않는 payload와 범위 초과의 처리를 profile에 명시한다. |
해당 editor·Editing |
| EG-HISTORY |
한 사용자 작업의 Undo 단위를 명시한다. local History는 다른 변경이 개입하지 않은 undo/redo에서 기록된 document와 Selection을 복원한다. selection-only·no-op은 새 문서 History entry를 만들지 않는다. |
Editing·선택한 History owner |
| EG-GESTURE |
구조적 gesture의 preview는 아직 확정되지 않은 결과다. commit은 그 preview에 해당하는 작업을 한 번 실행하고 cancel은 이를 실행하지 않는다. |
Affordance·해당 editor 연결 |
| EG-RESULT |
각 편집 결과와 발행 snapshot은 그 편집의 value·selection·history 상태를 함께 설명한다. 재진입이나 외부 변경으로 더 최신 상태가 생겨도 이전 결과의 의미를 덮어쓰지 않는다. |
Editing |
EG-EDIT의 실패 보장은 해당 의도가 만든 효과에 적용한다. 이미 받아들인 외부
document 변경을 실패한 의도 때문에 되돌리지 않는다. 이를 확인할 때 외부
변경 동기화와 새 의도 실행의 관찰 시점을 분리한다.
EG-CUT은 OS clipboard와 문서 사이의 분산 transaction을 약속하지 않는다.
Headless cut()은 보존 가능한 payload를 반환하고, Web event binding은 payload를
쓴 뒤 제거를 실행한다. Clipboard 쓰기 실패, 제거 거절, 성공한 후의 Undo를
서로 다른 결과로 검증한다. 브라우저가 custom edit를 다시 실행하지 않도록 하는
event ownership은 Web이 소유한다.
EG-HISTORY에서 외부 변경 이후의 의미는 선택한 History 계약을 따른다. 현재
local inverse History는 이를 비우며, collaboration History는 내 기여를 선택적으로
되돌린다. 둘을 같은 복원 알고리즘으로 고정하지 않는다. 이미 존재하는
EditingHistory를 사용하고 여러 Hand가 공유하는 작업 단위도 그 owner가 정한다.
EG-GESTURE는 구조 편집 preview에 대한 규칙이다. IME의 중간 DOM mutation과
composition grouping은 DOM 편집 lifecycle의 별도
계약을 따른다. createGestureSession의 존재만으로 Host의 preview가 문서를
변경하지 않는다고 증명할 수 없으므로 실제 연결까지 검증한다.
Hands profile이 반드시 결정할 내용
각 profile은 다음 질문에 하나의 답 또는 명시적인 설정별 답을 제공한다. 이는
문서와 적합성 사례의 항목이며 새로운 runtime descriptor type은 아니다.
- 대상: 무엇을 편집하며 어떤 identity와 위치 단위를 사용하는가?
- 선택: 사용할 family, primary의 의미, 여러 범위 처리, focus와 선택의 관계는?
- Topology: 가시 순서와 전체 대상 집합 중 무엇을 각 작업에 사용하는가?
- 작업: Select, Insert, Delete/Clear, Copy, Cut, Paste, Undo/Redo 중 무엇을
지원하며, 미지원 작업은 왜 해당 profile의 사용 목적과 양립하는가?
- 결과: 삭제 후 선택, 붙여넣기 위치·대체 규칙, 범위 초과, 새 identity는?
- History: typing·composition·drag의 작업 경계와 외부 변경의 처리 방식은?
- 입력: 선택한 플랫폼 관습, 편집 중인 text field와 구조 탐색의 우선순위는?
unsupported와 일시적으로 unavailable인 상태를 구별한다. Cut이 없는 editor와
선택이 없어 Cut을 할 수 없는 editor는 같은 계약이 아니다. API나 UI에서 지원을
선언한 작업은 동일한 지원 범위의 적합성 사례를 가져야 한다. 미지원 선언만으로
기대되는 기본 편집 흐름을 생략할 수 없으며, 그 선택의 외부 관습이나 제품 목적을
profile에서 설명한다.
현재 구현을 설명하는 대표 매핑
이 표는 현재 동작의 관찰이다. 관찰된 기본값이 곧 영구히 고정할 규칙은 아니다.
| 항목 |
Document |
Sheet |
Rich Text |
| 편집 단위 |
stable ID를 가진 블록과 text |
stable row/column ID의 셀 |
stable node ID와 text/child point |
| Copy 대상 |
선택된 블록 전체 |
primary rectangle |
선택된 structured slice |
| Paste |
기본적으로 마지막 선택 블록 뒤에 삽입 |
focus 셀부터 고정 경계 안에 기록 |
선택 구간과 schema에 맞게 slice 삽입 |
| 제거 |
선택 블록 제거 |
Cut은 primary rectangle 값을 null로 비움 |
선택 구간 제거·schema 제약 적용 |
| 후속 선택 |
삽입 블록 범위, 삭제 후 남은 이웃 |
붙여넣은 직사각형, Cut은 기존 선택 |
transform 후 mapping된 text/child point |
현재 binding은 각각 json-document-editing/src/document.ts, sheet.ts,
json-document-rich-text/src/editor.ts에 있다. Document의 text offset이 블록
Copy를 부분 문자열 Copy로 바꾸지는 않는다. Sheet의 primary rectangle 정책도
여러 범위 전체의 Copy와 구별한다. 이런 차이는 profile 이름과 사용법에서 드러나야
하며, 공통 함수 이름 때문에 사용자가 동일한 대상을 예상하게 해서는 안 된다.
구현에서 계약으로 옮길 때의 결정
| 현재 증거 |
설계 결정 |
동결 전 확인할 증거 |
Document selection.move는 블록을 옮김 |
navigation과 content movement를 의미 어휘에서 구별한다. 현재 identifier 변경은 별도 binding 변경으로 다룬다. |
위치 이동은 document 불변, 블록 이동은 identity 보존·Undo 복원 |
selectAllAffordance는 Mod+A 재입력 시 clear |
Select All의 공통 의미는 대상 전체 선택이다. 재입력 토글은 이를 선택한 입력 profile의 매핑으로만 취급한다. |
같은 select-all 의도의 반복은 같은 선택; 토글 profile은 두 번째 키 입력을 clear 의도로 변환 |
Database cut 부재가 테스트에 고정됨 |
현재 binding의 미지원으로 기록한다. 이를 모든 Database의 영구 문법으로 일반화하지 않는다. |
Database profile에서 Cut 생략 근거 또는 지원 동작을 정한 뒤 admission 판정 |
historyGroup과 external History가 공존 |
작업 묶음 정책과 기록·복원 메커니즘을 구별한다. external History owner가 step을 결정한다. |
같은 drag/composition 사례를 선택한 History owner에 연결한 결과 |
EditingIntent는 type: string |
공통 contract test로 의미를 고정하고 실제 호출은 각 editor의 기존 API로 번역한다. |
dispatch, copy, cut, undo, redo를 각 owner public API로 실행 |
새로운 전역 command union이나 capability registry는 이 문제를 해결하는 전제가
아니다. 이미 다른 의미를 가진 호출들을 한 이름으로 합치면 대상과 결과의 차이가
숨는다. 공통 protocol은 공유하는 규칙에 두고, 문서의 의미는 기존 owner에 둔다.
적합성 설계
테스트의 단위는 함수 유무가 아니라 시작 상태 → 의미 있는 작업 → 관찰 결과다.
Owner package의 테스트 harness가 public API에 작업을 연결한다. Harness는 자체
편집 로직을 구현하지 않고 호출과 결과의 정규화만 수행한다.
공통 rule의 vector와 runner는 해당 owner의 tests/conformance/에 두고, 장르별
fixture와 API binding은 해당 editor owner에 둔다. 기존 Rich Text versioned
vectors와 Core suite는 원래 owner와 경로를 유지한다. 기존 unit test의 기대값을
복사하는 대신 공통 rule에 해당하는 사례를 공용 runner로 승격한다.
| 사례 |
작업 |
관찰할 결과 |
현재 근거와 추가 검증 |
| 선택 후 확장 |
A 선택 → C까지 확장 |
anchor A 유지, profile topology의 대상, document·History 불변 |
Selection range tests → 여러 editor의 같은 rule binding |
| Copy의 무변경성 |
선택 → Copy 두 번 |
같은 의미의 payload, value·selection·Undo/Redo 불변 |
clipboard surface test의 payload 확인에 상태 불변 관찰 추가 |
| 편집과 복원 |
선택 → 허용된 변경 → Undo → Redo |
각 단계의 value·selection·availability, snapshot 순서 |
session history tests → Document·Sheet·Rich Text public binding |
| 거절의 원자성 |
경계 밖 Paste 또는 schema 거절 |
해당 작업의 partial value·selection·History·notification이 남지 않음 |
Sheet와 Rich Text rejection 사례를 같은 관찰 계약에 연결 |
| Cut의 실패 경계 |
clipboard 쓰기 실패 / 제거 거절 |
전자는 제거 미호출, 후자는 문서 불변·실패 결과 |
Web clipboard rejection tests에 쓰기 실패 사례 연결 |
| Gesture 취소 |
begin → preview 여러 번 → cancel |
확정 문서·History 불변, gesture 비활성 |
gesture unit test와 실제 editor 연결을 함께 검증 |
| 반복 전체 선택 |
select-all 두 번 |
같은 범위의 선택 유지 |
KeySelection rule과 입력 profile의 토글 매핑을 별도로 검증 |
| 외부 변경 |
선택·편집 후 외부 삭제 → 읽기/구독 |
profile의 유효한 선택, 선택한 History owner의 상태 |
external-selection/session tests와 History binding 구분 |
각 사례는 document, selection, History availability/대상, 발행 snapshot, clipboard
결과를 관찰한다. JSON-equal value, profile의 논리적 대상과 작업 순서를 비교한다.
Object identity, 내부 cache, snapshot 객체의 정확한 key 집합은 적합성 기준으로
추가하지 않는다. Failure code와 optional field는 owning contract의 규칙을 따른다.
새 identity를 생성하는 작업은 ID 문자열 자체의 일치를 요구하지 않는다. 입력에
이미 있던 ID는 정확히 보존하고, 새 ID만 결과 사이의 일대일 대응으로 비교하며
문서·Selection·clipboard 내부 참조에도 같은 대응을 적용한다. Harness의 이 정규화는
잘못된 대상 선택, identity 재사용, 순서·내용 손실을 숨겨서는 안 된다.
통과 보고서는 rule → profile → public binding → vector → 결과를 추적할 수 있어야
한다. 공용 runner가 한 구현의 내부 model을 요구하거나 Host가 기대 결과를 만들기
위해 edit를 재구현하면 이 설계가 실패한 것이다. 여러 장르의 구현을 통과한 결과는
규칙의 적용 가능성 증거이며 같은 profile의 독립 구현 간 상호운용 증거와 구별한다.
장기 호환성
약속하는 것은 고정된 profile의 지원 입력과 관찰 가능한 결과다. 같은 profile
revision 아래에서 target·selection·Undo 경계·failure/fallback 의미를 바꾸지 않는다.
새 API나 기능이 필요하면 기존 소비자의 결과를 보존하는 추가 계약으로 제공한다.
- Profile 식별과 version은 정본 문서에 우선 둔다. 모든 JSON payload에 공통
envelope나 version field를 추가하지 않는다. 기존 Rich Text profile URI 같은
저장 계약은 그 owner가 유지한다.
- 지원 입력을 넓혀 기존의 거절·fallback을 성공 처리로 바꾸는 것도 호환성 검토
대상이다. 의미를 보존하지 못하면 별도 profile revision으로 제공한다.
- 모호함이 발견되면 서로 다른 해석의 반례를 먼저 남긴다. 명확한 기존 규칙 위반은
구현 수정으로, 기존 규칙이 여러 동작을 허용했다면 profile 변경으로 판단한다.
- 이전 profile의 vectors와 실제 소비자 binding을 보존해 새 구현에서도 실행한다.
Current tests를 새 동작에 맞춰 일괄 수정한 것은 호환성 증거가 아니다.
- 구현 알고리즘·cache·DOM rendering은 이 결과를 보존하는 범위에서 바꿀 수 있다.
Stable admission에는 공통 rule과 profile의 필수 작업이 모두 실행되고, 각 책임의
public API·owner reference·site Usage·source registration이 연결돼야 한다. 같은
profile의 독립 구현, 특히 명세 작성자 밖의 구현 경험에서 생긴 해석 차이를 해결해야
장기 상호운용성의 근거가 된다. 사이트의 한 Demo나 내부 테스트 통과로 이를 대체하지
않는다.
비용과 재검토 조건
이 설계는 profile별 선택과 compatibility corpus를 유지하는 비용을 만든다.
그 비용을 줄이기 위해 실행 구조를 하나로 통일하는 대신 현재 owner의 runner를
공유하고, 실제 지원하는 profile만 약속한다. 모든 장르에 한 Selection shape를
강제하는 대안은 text range·grid rectangle·object set의 의미를 잃으므로 채택하지
않는다.
다음 관찰은 설계를 다시 검토할 근거다.
- 공통 rule이 기존의 타당한 편집 관습을 표현하지 못하면 해당 rule을 profile
선택으로 내리거나 사전 조건을 바로잡는다.
- 한 역할의 구현이 여러 Host에 남으면 기존 owner API의 부족 여부부터 확인한다.
- 규칙을 검증하려고 Core에 편집 상태를 넣어야 한다면 owner 분리가 잘못된 것이다.
- 같은 profile의 두 구현이 모두 suite를 통과해도 소비자 결과가 다르면 누락된
관찰 항목을 반례로 추가한다.
외부 근거
Goal Anchor
사용자가 설계 개선 후 “진행해”로 실행을 승인했다. 아래는 승인한 설계 원문이다. 설계 문서의 Done은 설계 산출물의 기준이며, 이 실행은 그 적합성 설계를 기존 owner에서 구현하는 후속 단계다. 이름 변경이나 미지원 명령 추가는 포함하지 않는다.
현재 #719 / PR #720이 소유한 세션 오류 복구·구독·협업 History 변경은 별도 작업으로 유지한다.
승인한 설계와 결정 원문
편집 문법의 안정화 설계
상태: Design Draft. 기존 public API와 Stable profile의 의미는 유지한다.
이 문서는 공통 편집 규칙의 소유자, Hands별 해석, 적합성 증거를 설계한다.
아래 제안의 구현 완료나 외부 상호운용성을 주장하지 않는다.
목표와 범위
오랫동안 정착한 편집 문법을 구현과 제품이 바뀌어도 유지되는 계약으로 만든다.
작은 Core는 장기간 약속할 수 있는 의미만 소유한다. JSON Document의 여섯
member와 편집 문법의 크기는 서로 다른 문제다.
관찰 가능한 의미를 얻는다.
현재 구현과의 차이, 이를 판정할 적합성 사례를 연결한다.
범용 editor, command bus, profile registry나 package hierarchy를 만들지 않는다.
구현 근거의 범위는 JSON Document, Selection, Editing, Affordance, Web과
Document·Sheet·Rich Text의 대표 편집 경로다. Object의 전체 선택과 Database의
cut 미지원은 profile 차이를 판정하는 사례로 포함한다. 모든 Hands의 완성도,
브라우저별 입력 일치, 협업 wire protocol의 수렴은 이 설계의 검증 결과가 아니다.
현재 문제와 원인
EditingSession은 value·selection·history를 함께 처리하고 Selection family는대상의 전이를 공유한다. 그러나
EditingIntent의 공통 계약은type: string과dispatch형태이며, 동사의 사전 조건과 결과는 editor별 코드와 문서에 있다.Official Hands도 아직 호환성 약속을 확정하지 않은 후보다.이 때문에 여러 editor가 같은 API 형태를 제공해도 같은 편집 문법을 따른다는
증거가 되지 않는다.
selectAllAffordance의 전체 선택 토글처럼 특정 관습이범용 기본값으로 보이고,
selection.move처럼 문서 변경과 선택 변경이 이름에서구별되지 않는 사례도 있다. 동작을 선언하는 규칙과 그 규칙을 검증하는 사례의
연결이 부족한 것이 원인이다.
세 종류의 계약과 기존 소유자
다음은 새 runtime 계층이 아니라 기존 책임들이 약속할 내용의 구분이다.
이는 대표적인 값 변경 흐름이다. Copy는 조회이며, 선택만 바꾸는 작업은 document
commit을 만들지 않고, Undo/Redo는 선택한 History owner를 실행한다. 순수 JSON
소비자에게 Editing이나 Hands 설치를 요구하지 않는다.
json-documentjson-document-selectionjson-document-editingEditingPlan, snapshot, transaction, local History, external History 연결json-document-affordancejson-document-web및 text Web AdapterDocument Type은 책임 이름이며 이 표로 package 재배치를 승인하지 않는다. 현재
Document·Sheet 등은 Editing에, Rich Text는 자신의 package에 구현돼 있다.
Hands는 기존 공개 API들의 함께 검증된 조합이다. Host는 제품 데이터·권한·copy·
layout·concrete external instance와 조합을 소유한다.
공통으로 고정할 편집 규칙
아래 ID는 설계 요구사항이다. 실제 동결은 owner의 versioned 계약과 적합성
증거를 통해 이루어진다. DOM API 모양, JSON 저장 shape, 특정 키 조합은 이
규칙의 전제가 아니다.
selectionAfter를 한 편집 결과로 발행한다. 실패한 의도는 자신의 partial mutation·selection·History entry를 남기지 않는다.EG-EDIT의 실패 보장은 해당 의도가 만든 효과에 적용한다. 이미 받아들인 외부
document 변경을 실패한 의도 때문에 되돌리지 않는다. 이를 확인할 때 외부
변경 동기화와 새 의도 실행의 관찰 시점을 분리한다.
EG-CUT은 OS clipboard와 문서 사이의 분산 transaction을 약속하지 않는다.
Headless
cut()은 보존 가능한 payload를 반환하고, Web event binding은 payload를쓴 뒤 제거를 실행한다. Clipboard 쓰기 실패, 제거 거절, 성공한 후의 Undo를
서로 다른 결과로 검증한다. 브라우저가 custom edit를 다시 실행하지 않도록 하는
event ownership은 Web이 소유한다.
EG-HISTORY에서 외부 변경 이후의 의미는 선택한 History 계약을 따른다. 현재
local inverse History는 이를 비우며, collaboration History는 내 기여를 선택적으로
되돌린다. 둘을 같은 복원 알고리즘으로 고정하지 않는다. 이미 존재하는
EditingHistory를 사용하고 여러 Hand가 공유하는 작업 단위도 그 owner가 정한다.EG-GESTURE는 구조 편집 preview에 대한 규칙이다. IME의 중간 DOM mutation과
composition grouping은 DOM 편집 lifecycle의 별도
계약을 따른다.
createGestureSession의 존재만으로 Host의 preview가 문서를변경하지 않는다고 증명할 수 없으므로 실제 연결까지 검증한다.
Hands profile이 반드시 결정할 내용
각 profile은 다음 질문에 하나의 답 또는 명시적인 설정별 답을 제공한다. 이는
문서와 적합성 사례의 항목이며 새로운 runtime descriptor type은 아니다.
지원하며, 미지원 작업은 왜 해당 profile의 사용 목적과 양립하는가?
unsupported와 일시적으로unavailable인 상태를 구별한다. Cut이 없는 editor와선택이 없어 Cut을 할 수 없는 editor는 같은 계약이 아니다. API나 UI에서 지원을
선언한 작업은 동일한 지원 범위의 적합성 사례를 가져야 한다. 미지원 선언만으로
기대되는 기본 편집 흐름을 생략할 수 없으며, 그 선택의 외부 관습이나 제품 목적을
profile에서 설명한다.
현재 구현을 설명하는 대표 매핑
이 표는 현재 동작의 관찰이다. 관찰된 기본값이 곧 영구히 고정할 규칙은 아니다.
null로 비움현재 binding은 각각
json-document-editing/src/document.ts,sheet.ts,json-document-rich-text/src/editor.ts에 있다. Document의 text offset이 블록Copy를 부분 문자열 Copy로 바꾸지는 않는다. Sheet의 primary rectangle 정책도
여러 범위 전체의 Copy와 구별한다. 이런 차이는 profile 이름과 사용법에서 드러나야
하며, 공통 함수 이름 때문에 사용자가 동일한 대상을 예상하게 해서는 안 된다.
구현에서 계약으로 옮길 때의 결정
selection.move는 블록을 옮김selectAllAffordance는 Mod+A 재입력 시 clearcut부재가 테스트에 고정됨historyGroup과 external History가 공존EditingIntent는type: stringdispatch,copy,cut,undo,redo를 각 owner public API로 실행새로운 전역 command union이나 capability registry는 이 문제를 해결하는 전제가
아니다. 이미 다른 의미를 가진 호출들을 한 이름으로 합치면 대상과 결과의 차이가
숨는다. 공통 protocol은 공유하는 규칙에 두고, 문서의 의미는 기존 owner에 둔다.
적합성 설계
테스트의 단위는 함수 유무가 아니라 시작 상태 → 의미 있는 작업 → 관찰 결과다.
Owner package의 테스트 harness가 public API에 작업을 연결한다. Harness는 자체
편집 로직을 구현하지 않고 호출과 결과의 정규화만 수행한다.
공통 rule의 vector와 runner는 해당 owner의
tests/conformance/에 두고, 장르별fixture와 API binding은 해당 editor owner에 둔다. 기존 Rich Text versioned
vectors와 Core suite는 원래 owner와 경로를 유지한다. 기존 unit test의 기대값을
복사하는 대신 공통 rule에 해당하는 사례를 공용 runner로 승격한다.
각 사례는 document, selection, History availability/대상, 발행 snapshot, clipboard
결과를 관찰한다. JSON-equal value, profile의 논리적 대상과 작업 순서를 비교한다.
Object identity, 내부 cache, snapshot 객체의 정확한 key 집합은 적합성 기준으로
추가하지 않는다. Failure code와 optional field는 owning contract의 규칙을 따른다.
새 identity를 생성하는 작업은 ID 문자열 자체의 일치를 요구하지 않는다. 입력에
이미 있던 ID는 정확히 보존하고, 새 ID만 결과 사이의 일대일 대응으로 비교하며
문서·Selection·clipboard 내부 참조에도 같은 대응을 적용한다. Harness의 이 정규화는
잘못된 대상 선택, identity 재사용, 순서·내용 손실을 숨겨서는 안 된다.
통과 보고서는
rule → profile → public binding → vector → 결과를 추적할 수 있어야한다. 공용 runner가 한 구현의 내부 model을 요구하거나 Host가 기대 결과를 만들기
위해 edit를 재구현하면 이 설계가 실패한 것이다. 여러 장르의 구현을 통과한 결과는
규칙의 적용 가능성 증거이며 같은 profile의 독립 구현 간 상호운용 증거와 구별한다.
장기 호환성
약속하는 것은 고정된 profile의 지원 입력과 관찰 가능한 결과다. 같은 profile
revision 아래에서 target·selection·Undo 경계·failure/fallback 의미를 바꾸지 않는다.
새 API나 기능이 필요하면 기존 소비자의 결과를 보존하는 추가 계약으로 제공한다.
envelope나 version field를 추가하지 않는다. 기존 Rich Text profile URI 같은
저장 계약은 그 owner가 유지한다.
대상이다. 의미를 보존하지 못하면 별도 profile revision으로 제공한다.
구현 수정으로, 기존 규칙이 여러 동작을 허용했다면 profile 변경으로 판단한다.
Current tests를 새 동작에 맞춰 일괄 수정한 것은 호환성 증거가 아니다.
Stable admission에는 공통 rule과 profile의 필수 작업이 모두 실행되고, 각 책임의
public API·owner reference·site Usage·source registration이 연결돼야 한다. 같은
profile의 독립 구현, 특히 명세 작성자 밖의 구현 경험에서 생긴 해석 차이를 해결해야
장기 상호운용성의 근거가 된다. 사이트의 한 Demo나 내부 테스트 통과로 이를 대체하지
않는다.
비용과 재검토 조건
이 설계는 profile별 선택과 compatibility corpus를 유지하는 비용을 만든다.
그 비용을 줄이기 위해 실행 구조를 하나로 통일하는 대신 현재 owner의 runner를
공유하고, 실제 지원하는 profile만 약속한다. 모든 장르에 한 Selection shape를
강제하는 대안은 text range·grid rectangle·object set의 의미를 잃으므로 채택하지
않는다.
다음 관찰은 설계를 다시 검토할 근거다.
선택으로 내리거나 사전 조건을 바로잡는다.
관찰 항목을 반례로 추가한다.
외부 근거
Undo/Redo·Cut/Copy/Paste·Select All·Delete의 정착된 명령 어휘. 모든 장르의
정확한 selection·paste·history 알고리즘을 규정하는 자료는 아니다.
focus와 selection의 구별, 예측 가능한 navigation. APG는 구현 지침이다.
복수 selection model과 선택 가능한 Ctrl+A 토글은 입력 관습이 하나가 아님을 보여준다.
물리 입력과 편집 의도의 구분을 참고한다. Working Draft의 event API를 영구 계약으로
채택하지 않으며 구조 편집 전체의 의미로 확대하지 않는다.
확장과 오류 처리를 명확히 규정하고 해석 차이를 유지보수로 해결하는 근거다.
명세 작성자 이외의 구현과 실제 상호운용 경험을 별도 증거로 요구하는 근거다.