Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ schema -> document -> pointer/query -> can* -> change -> result
| 문서 구조 | [docs/README.md](docs/README.md) |
| 변경 기록 | [docs/changelog.md](docs/changelog.md) |
| core 의미론 명세 | [docs/standard/json-document-spec.md](docs/standard/json-document-spec.md) |
| 1.0 conformance profile | [docs/standard/conformance-profile.md](docs/standard/conformance-profile.md) |
| result/error 계약 | [docs/standard/result-contract.md](docs/standard/result-contract.md) |
| selection 계약 | [docs/standard/selection-contract.md](docs/standard/selection-contract.md) |
| schema introspection 계약 | [docs/standard/schema-introspection-contract.md](docs/standard/schema-introspection-contract.md) |
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ docs
| `-- recipes.md # 제품별 feature coverage 지도
`-- standard
|-- core-standard.md # 표준 후보 계약
|-- conformance-profile.md # 1.0 compatibility profile
|-- contract-pressure-register.md
|-- extension-delegation-standard.md
|-- foundation-gate.md # foundation 판정 기준
Expand Down
138 changes: 138 additions & 0 deletions docs/standard/conformance-profile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# json-document 1.0 Conformance Profile

상태: 1.0 정식화 기준.

이 문서는 `@interactive-os/json-document` 1.0 호환성을 무엇으로 검증할지
정의한다. 목표는 새 public API를 만드는 것이 아니라, 이미 고정된 public API
계약을 외부 구현체와 유지보수자가 같은 기준으로 읽게 만드는 것이다.

1.0의 conformance profile은 문서화된 profile이다. 별도 npm package, CLI runner,
외부 구현체용 harness는 1.0 범위에 포함하지 않는다. 그런 artifact는 나중에 만들
수 있지만, 1.0 core API 안정화의 선행 조건은 아니다.

## 규범

`MUST`, `MUST NOT`, `SHOULD`, `SHOULD NOT`, `MAY`는 규범 키워드다.

`json-document compatible`을 주장하는 구현체는 public package entrypoint만으로
이 profile의 의미론을 만족해야 한다. 구현체는 consumer에게 source path,
private module, test helper, dist 내부 파일 import를 요구하면 안 된다.

## Profile Class

| Profile | 대상 entrypoint | 의미 |
| --- | --- | --- |
| Core | `@interactive-os/json-document` | headless document foundation 표면 |
| React | `@interactive-os/json-document/react` | 같은 document 표면을 React hook으로 노출 |

React profile은 선택적이다. Core profile을 통과하지 못한 구현체는 React profile을
주장할 수 없다.

## 1.0 Profile Artifact

1.0 conformance는 다음 artifact 묶음으로 정의한다.

| Artifact | 역할 |
| --- | --- |
| `docs/standard/core-standard.md` | public semantics의 규범 기준 |
| `docs/standard/result-contract.md` | result shape, stable error code, diagnostic 기준 |
| `docs/standard/selection-contract.md` | headless selection snapshot과 patch tracking 기준 |
| `docs/standard/schema-introspection-contract.md` | schema query, `schema-slot`, `document-result` 기준 |
| `packages/json-document/public-contract.json` | public export name lock |
| `packages/json-document/tests/public/signature-contract.test-d.ts` | overload와 call shape lock |
| `packages/json-document/tests/public/semantic-contract.test.ts` | strict 기본값, atomicity, clipboard spread, selection/history round-trip fixture |
| `packages/json-document/tests/public/result-contract.test.ts` | result code와 success result shape fixture |
| `packages/json-document/tests/public/standard-conformance.test.ts` | public entrypoint 기반 broad conformance scenario |
| `packages/json-document/tests/public/json-patch/*` | RFC 6902 JSON Patch 공개 동작 |
| `packages/json-document/tests/public/json-pointer/*` | RFC 6901 JSON Pointer 공개 동작 |
| `packages/json-document/tests/public/jsonpath/*` | JSONPath 검색 공개 동작 |

이 artifact들은 서로 다른 층을 잠근다.

```txt
conformance profile
|-- export lock: 이름이 사라지지 않는다
|-- signature fixture: 호출 모양과 overload가 유지된다
|-- semantic fixture: 1.0 이후 바뀌면 breaking인 예시를 고정한다
|-- result fixture: code와 result shape로 분기할 수 있다
|-- standard conformance: public entrypoint만으로 foundation 흐름을 검증한다
`-- protocol fixtures: JSON Patch, Pointer, JSONPath 의미론을 검증한다
```

## 포함되는 의미론

Core profile은 다음 의미론을 포함해야 한다.

- JSON data boundary와 JSON-serializable public payload.
- JSON Pointer 주소와 JSONPath 검색의 구분.
- RFC 6902 JSON Patch 실행과 실패 atomicity.
- schema validation과 schema introspection.
- `strict: false` 기본값과 `strict: true` throwing boundary.
- `can*` capability purity와 reasoned result.
- document mutation result shape와 stable error code.
- headless selection snapshot, `selectionAfter`, patch tracking.
- document-owned clipboard buffer와 payload-only paste.
- undo/redo history round-trip.
- public root helper의 pure patch behavior.

## 포함하지 않는 것

다음은 1.0 conformance profile의 일부가 아니다.

- 별도 `@interactive-os/json-document-conformance` package.
- 외부 구현체용 CLI runner.
- private source path 또는 implementation-only helper.
- `dist/` 파일 구조.
- demo app, site, browser test, Playwright fixture.
- official extension, lab extension, product recipe의 동작.
- performance budget.
- DOM focus, rendering, keyboard, system clipboard permission, storage backend.

Extension은 core profile 위에서 compose되어야 하지만, extension test를 통과했다고
core compatible을 주장할 수는 없다. 반대로 core profile이 extension public API를
자동으로 고정하지도 않는다.

## 실행 기준

이 repo의 1.0 release gate는 다음 명령을 통해 profile과 관련 artifact를 검증한다.

```sh
npm run standard:check
npm run docs:evaluate
npm test -w @interactive-os/json-document -- semantic-contract result-contract standard-conformance
npm run typecheck -w @interactive-os/json-document
```

`npm run standard:check`는 표준 문서, conformance scenario, semantic fixture,
signature fixture, public export lock이 서로 분리되지 않았는지 확인한다.

## 변경 기준

다음 변경은 conformance profile 관점에서 breaking change다.

- public export 제거 또는 rename.
- public overload와 call shape 변경.
- 기존 stable error code 제거, rename, 의미 변경.
- success result shape 의미 변경.
- failed mutation이 state, selection, clipboard, history, subscriber를 부분 변경하게 됨.
- `schema-slot`과 `document-result` violation path 기준 변경.
- `selectionAfter`보다 auto tracking을 우선하도록 변경.
- payload-only core clipboard/paste 의미론 변경.

다음 변경은 별도 검토 후 minor일 수 있다.

- 새 optional result diagnostic field.
- 새 error code 추가.
- 새 `SchemaKind` 추가.
- 새 conformance scenario 추가.

## 보류된 artifact

별도 conformance package나 runner는 보류한다. 보류 이유는 다음이다.

- 1.0에서 public API surface를 더 늘리지 않는다.
- 현재 목표는 외부 구현체 지원 tooling보다 public contract freeze다.
- profile이 문서와 fixture로 충분히 안정된 뒤에야 runner API도 안정적으로 설계할 수 있다.

추후 runner를 만든다면 이 문서의 profile을 source of truth로 삼아야 하며,
runner가 새로운 의미론 계약을 추가하면 안 된다.
34 changes: 24 additions & 10 deletions docs/standard/contract-pressure-register.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Core 승격은 마지막 단계다. 다음 중 하나라도 불명확하면 core
| --- | --- | --- | --- |
| guard composition | `protected-ranges`, `proposed-changes`, `search-replace`, paste/drop 계열이 guard와 core capability 실패를 조합 | 부분 반영: `@interactive-os/json-document-protected-ranges` | 같은 guard result shape가 3개 이상 package에서 자연스럽게 맞는지 확인 |
| patch preview / dry-run | `patch-preview`, `document-diff`, `proposed-changes`, import/review workflow가 apply 전 next value를 요구 | 반영됨: `@interactive-os/json-document-patch-preview` | downstream dogfood에서 visual diff/review workflow가 host-owned로 남는지 확인 |
| structural change result | `grouping`, `wrap-selection`, `outline`, `bulk-edit`가 prospective operations와 execution result를 노출 | lab convention | `operations`, `selectionAfter`, `diagnostics` naming을 통일할 수 있는지 확인 |
| structural change result | `grouping`, `wrap-selection`, `outline`, `bulk-edit`가 prospective operations와 execution result를 노출 | **결정됨: extension convention** | Core API 변경 없음. 외부 extension에는 SHOULD, repo official/lab에는 MUST로 `operations`, `selectionAfter`, `diagnostics`를 소급 적용 |
| anchored pointer lifecycle | `comments`, `bookmarks`, `live-cursors`, review anchor가 `trackPointer` 이후 lost/recovered 상태를 반복 | 부분 반영: `@interactive-os/json-document-comments` | generic anchor lifecycle이 bookmark/presence 밖에서도 같은지 확인 |
| stable id to Pointer | Kanban, form builder, import/review, slide/layer selection, blind object editor review에서 반복 | 반영됨: `@interactive-os/json-document-id-resolver` | downstream dogfood에서 id policy가 host-owned로 남는지 확인 |
| invalid form draft | form builder, settings, CMS property panel, spreadsheet cell editing에서 valid JSON commit 전 temporary input이 반복 | 반영됨: `@interactive-os/json-document-form-draft` | parser/widget/focus policy가 host-owned로 남는지 확인 |
Expand All @@ -52,7 +52,7 @@ Core 승격은 마지막 단계다. 다음 중 하나라도 불명확하면 core
| lab result boilerplate | 여러 lab이 `capabilityError`/`patchError`/`error`/`cloneJson` helper를 반복 | lab convention | helper 모양만으로 shared package/core를 만들지 않는다. 같은 실패 의미론이나 실행 단계가 반복될 때만 후보로 기록 |
| command-sized feature granularity | `pad-text`, `trim-text`, `round`, `limit-items` 같은 단일 field/array command lab이 빠르게 증가 | reusable command feature | 편집도구 command로 이름 붙일 수 있으면 feature다. package 배포 단위와 feature 판정은 분리 |
| semantic contract lock | export lock은 이름만 고정하고 signature/error literal 의미론은 문서와 테스트가 고정 | evaluator 후보 | signature snapshot 또는 semantic fixture를 추가할지 확인 |
| structural object commands | grouping, wrap/unwrap, layer order가 slide/diagram/object editor에서 반복 | official 후보 | 같은 `operations`/`selectionAfter` result shape로 승격 가능한지 확인 |
| structural object commands | grouping, wrap/unwrap, layer order가 slide/diagram/object editor에서 반복 | official/lab convention | `operations`/`selectionAfter`는 extension convention으로 고정. 개별 package 승격은 별도 증거 필요 |
| sibling-range 정규화 | "선택된 sibling pointer → {공유 parent, 정렬 index, 연속성}" 를 `fill-series`·`move-selected`·`grouping`·`wrap-selection`·`layer-order` 5개 독립 확장이 재구현. `grouping`/`wrap-selection`의 resolver는 byte 단위 동일 | **반영됨: core `resolveSiblingRange` (#95)** | 순수 path helper로 core 승격(#95), 5개 소비자 모두 수렴(#96/#97/#98). `drag-drop`은 단일 source/target 개별 해석이라 range 대상이 아님(하위 primitive 사용, 제외). 남은 후보: 에러 코드 통일(현재 각 확장이 helper 코드를 자기 코드로 매핑) |

## Guard Composition
Expand Down Expand Up @@ -108,8 +108,11 @@ plan pressure

- `patch-preview`는 `@interactive-os/json-document-patch-preview` official extension으로 승격했다.
- `PatchPlan`은 core 타입으로 만들지 않는다.
- lab에서는 `operations`, `preview`, `apply`, `diagnostics`, `selectionAfter`를
같은 의미로 쓰는지 확인한다.
- structural command 계열은 `operations`, `selectionAfter`, `diagnostics`를
convention으로 쓴다. 외부 extension에는 SHOULD, 이 repo의 official/lab에는
MUST다.
- `preview`와 `apply`는 feature가 preview/execution boundary를 노출할 때의
method 이름 후보이지, 모든 structural result의 공통 field가 아니다.

최소 공유 어휘 후보:

Expand All @@ -121,6 +124,13 @@ plan pressure
| `diagnostics` | 실행을 막지는 않지만 adapter/import/paste에서 알려야 하는 정보 |
| `selectionAfter` | 구조 편집 후 host가 focus/selection을 옮길 Pointer |

Repo 내부 audit 결과 `grouping`, `outline`, `bulk-edit`, `proposed-changes`,
`wrap-selection`, `move-selected`, `layer-order`, `fill-series`, `grid-range`,
`paste-cells`, `batch-update`, `clear-contents`, `fill-blanks`는 이미
`operations`와 필요한 경우 `selectionAfter`로 수렴했다. `paste-special`,
`id-resolver`, `references`는 비차단 정보를 `diagnostics`로 노출한다.
따라서 이 항목은 core 승격 후보가 아니라 extension surface convention이다.

## Anchor Lifecycle

Core `trackPointer`는 patch 이후 Pointer를 추적한다. 그러나 comment, bookmark,
Expand Down Expand Up @@ -310,14 +320,14 @@ delegation lens

| Lab | Delegation | App-owned residue | Midcheck action |
| --- | --- | --- | --- |
| `autosave` | partial | host save transport, scheduler, retry/offline/conflict policy가 큼 | coalescing/status는 위임됐지만 "autosave" 기대치에는 retry/backoff/offline profile 후보가 남음 |
| `autosave` | partial | host save transport, scheduler, retry/offline/conflict policy가 큼 | **lab 유지**. coalescing/status는 위임됐지만 "autosave" 기대치에는 retry/backoff/offline profile 후보가 남음 |
| `batch-update` | strong | target selection, value/compute policy | 유지. batch atomicity, per-target patch, failure는 위임됨 |
| `bookmarks` | strong | bookmark names, persistence, focus sync | 유지. pointer tracking/lost state는 위임됨 |
| `checkpoints` | strong | persistence, retention, compare/restore UI | 유지. named snapshot/restore mechanics는 위임됨 |
| `clear-contents` | mostly | ambiguous enum/object empty policy | 유지. schema-derived clear는 위임됐고 `emptyFor`는 product policy |
| `convert-type` | strong | target type choice, locale-specific parsing beyond built-ins | 유지하되 command label은 `convert type` 후보 |
| `sort-items` | mostly | comparator/sort key, rendered sort UI | 유지. array replacement, reverse, can/execute는 위임됨 |
| `calculated-fields` | partial | formula definitions, dependency graph, scheduling | deepen 후보. 현재는 sync boundary 위임이고 "computed fields" 전체는 아직 host가 많이 앎 |
| `calculated-fields` | partial | formula definitions, dependency graph, scheduling | **lab 유지**. 현재는 sync boundary 위임이고 "computed fields" 전체는 아직 host가 많이 앎 |
| `convert-block-type` | mostly | kind descriptor, field preservation, default factory | 유지. conversion patch/failure는 위임됐고 schema-specific factory는 product policy |
| `toggle-value` | strong | optional custom order via `values` | 유지. boolean/closed-set toggle-value mechanics는 위임됨 |
| `dedupe` | mostly | duplicate key policy for objects | 유지. dedupe mechanics/atomicity는 위임됨 |
Expand All @@ -335,7 +345,7 @@ delegation lens
| `move-selected` | strong | source/target selection and focus | 유지. contiguous block move mechanics are delegated |
| `increment-number` | strong | rendered spinner/unit/formatting | 유지. numeric step/clamp mechanics are delegated |
| `pad-text` | strong | target choice, number formatting if needed | 유지. stored string padding mechanics are delegated |
| `paste-special` | partial | payload adaptation rules are the hard part and live in host adapter | deepen 후보. boundary/error preservation is delegated; common adapters may be needed for full feature delegation |
| `paste-special` | partial | payload adaptation rules are the hard part and live in host adapter | **lab 유지**. boundary/error preservation is delegated; common adapters may be needed for full feature delegation |
| `live-cursors` | mostly | realtime transport, identity/color policy, timeout | 유지. remote anchor tracking over patches is delegated |
| `references` | mostly | descriptor/readId/query policy, routing/remote lookup | 유지. indexing/backlink/set-reference mechanics are delegated |
| `renumber-items` | strong | when reorder has happened, field name | 유지. order-field sync mechanics are delegated |
Expand All @@ -349,9 +359,13 @@ delegation lens
| `wrap-selection` | mostly | wrapper shape factory, product container policy | 유지. wrap/unwrap range mechanics are delegated |

`partial`은 제거 판정이 아니다. 완전 위임이라는 제품 목표에서 다음에 깊게 만들
후보라는 뜻이다. 현재 우선순위는 `calculated-fields`, `paste-special`,
`autosave`다. 세 package 모두 이름은 feature로 유효하지만, host callback이
product policy 주입인지 feature 구현 위임 실패인지 더 확인해야 한다.
후보라는 뜻이다.

1.0 결정: `calculated-fields`, `paste-special`, `autosave`는 아직 lab으로
유지한다. Core API 변경은 없고, official 승격도 보류한다. 세 package 모두 이름은
feature로 유효하지만, host callback이 product policy 주입인지 feature 구현 위임
실패인지 더 확인해야 한다. 후속 작업은 승격 PR이 아니라 lab README와 recipe에서
host-owned residue를 더 선명하게 만드는 audit이다.

## Semantic Contract Lock

Expand Down
15 changes: 10 additions & 5 deletions docs/standard/core-standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ headless JSON 편집 도구의 foundation 계약으로 쓰일 수 있는지를

`MUST`, `MUST NOT`, `SHOULD`, `SHOULD NOT`, `MAY`는 규범 키워드다.

어떤 구현체가 json-document 호환이라고 주장하려면 이 문서와 적합성
suite를 통과해야 한다. README와 사이트 문서는 사용법을 설명할 수 있지만,
의미론 계약의 기준은 이 문서다.
어떤 구현체가 json-document 호환이라고 주장하려면 이 문서와
`docs/standard/conformance-profile.md`의 적합성 profile을 만족해야 한다.
README와 사이트 문서는 사용법을 설명할 수 있지만, 의미론 계약의 기준은
standard 문서다.

## 2. 범위

Expand Down Expand Up @@ -233,6 +234,10 @@ adapter가 새 core concept을 요구한다면 public requirement, 기존 concep

## 14. 적합성

1.0 적합성 기준은 `docs/standard/conformance-profile.md`가 정의한다. 이
profile은 문서화된 profile이며, 1.0에서는 별도 npm package나 CLI runner를
public artifact로 만들지 않는다.

적합성 suite는 public package entrypoint에서만 import해야 한다.

적합성 suite는 정상 동작, 실패 동작, atomicity, JSON serializability,
Expand All @@ -254,5 +259,5 @@ React `useJSONDocument` 초기값 overload처럼 사용자가 컴파일 시점
import해야 하며, implementation-private type이나 source path를 요구하면 안 된다.

일반 구현 테스트를 통과하는 것만으로는 표준 적합성을 주장할 수 없다.
json-document 호환 구현체는 implementation-private module 없이 적합성 suite를
통과해야 한다.
json-document 호환 구현체는 implementation-private module 없이 conformance
profile을 만족해야 한다.
Loading