@hatiolab/figure-model 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +3 -0
  3. package/dist/asset-types.d.ts +34 -3
  4. package/dist/asset-types.d.ts.map +1 -1
  5. package/dist/capabilities.js +28 -4
  6. package/dist/capabilities.js.map +1 -1
  7. package/dist/graph-types.d.ts +60 -1
  8. package/dist/graph-types.d.ts.map +1 -1
  9. package/dist/graph.d.ts.map +1 -1
  10. package/dist/graph.js +212 -21
  11. package/dist/graph.js.map +1 -1
  12. package/dist/index.d.ts +4 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +3 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/kernel-version.d.ts +1 -1
  17. package/dist/kernel-version.js +1 -1
  18. package/dist/names.d.ts +19 -0
  19. package/dist/names.d.ts.map +1 -0
  20. package/dist/names.js +47 -0
  21. package/dist/names.js.map +1 -0
  22. package/dist/package.d.ts +86 -0
  23. package/dist/package.d.ts.map +1 -0
  24. package/dist/package.js +202 -0
  25. package/dist/package.js.map +1 -0
  26. package/dist/render-lod.d.ts +12 -0
  27. package/dist/render-lod.d.ts.map +1 -0
  28. package/dist/render-lod.js +32 -0
  29. package/dist/render-lod.js.map +1 -0
  30. package/dist/shape-ops.d.ts +1 -1
  31. package/dist/shape-ops.d.ts.map +1 -1
  32. package/dist/shape-ops.js.map +1 -1
  33. package/dist/words.d.ts +6 -6
  34. package/dist/words.js +8 -8
  35. package/dist/words.js.map +1 -1
  36. package/docs/assembly-constraints.md +3 -3
  37. package/docs/asset-persistence.md +8 -8
  38. package/docs/authoring-transactions.md +2 -2
  39. package/docs/capability-bindings.md +1 -1
  40. package/docs/common-kernel-experiment.md +2 -2
  41. package/docs/completeness-review-2026-10-04.md +150 -1
  42. package/docs/core-semantics.md +2 -2
  43. package/docs/cutover.md +4 -4
  44. package/docs/document-contract.md +3 -3
  45. package/docs/dryroom-profile-validation.md +1 -1
  46. package/docs/editor-integration.md +4 -4
  47. package/docs/evaluation-changes-design.md +304 -0
  48. package/docs/evaluation-performance-summary-2026-10-05.md +236 -0
  49. package/docs/full-conveyor-validation.md +8 -8
  50. package/docs/full-dryroom-validation.md +5 -5
  51. package/docs/full-forklift-validation.md +5 -5
  52. package/docs/full-robot-validation.md +4 -4
  53. package/docs/layout-system.md +2 -2
  54. package/docs/legacy-risk-audit-2026-09-23.md +14 -14
  55. package/docs/minimal-model.md +3 -3
  56. package/docs/openusd-review.md +14 -14
  57. package/docs/operator-contracts.md +4 -4
  58. package/docs/performance-followup-2026-10-05.md +314 -0
  59. package/docs/prototypes/README.md +2 -2
  60. package/docs/prototypes/asset.schema.json +1 -1
  61. package/docs/prototypes/document.schema.json +1 -1
  62. package/docs/prototypes/editor-browser.mjs +2 -2
  63. package/docs/prototypes/linear-comparison.py +1 -1
  64. package/docs/prototypes/render-dryroom.py +1 -1
  65. package/docs/prototypes/render-full-dryroom.mjs +12 -12
  66. package/docs/prototypes/runtime-browser.mjs +3 -3
  67. package/docs/research-review.md +1 -1
  68. package/docs/review-2026-09-22.md +19 -19
  69. package/docs/runtime-extraction.md +10 -10
  70. package/docs/sample-validation-expanded.md +5 -5
  71. package/docs/sample-validation.md +5 -5
  72. package/docs/shape-dimension-contract.md +1 -1
  73. package/docs/spatial-contracts.md +2 -2
  74. package/docs/status.md +1 -1
  75. package/docs/storage-integration.md +5 -5
  76. package/package.json +1 -1
package/dist/words.js CHANGED
@@ -97,21 +97,21 @@ export const SEGMENT_PRESETS = [8, 12, 16, 24, 32, 48];
97
97
  /** The design inputs that stand for the figure's size, in mm. */
98
98
  export const FIGURE_SIZE_INPUTS = Object.freeze({ x: 'size.x', y: 'size.y', z: 'size.z' });
99
99
  /**
100
- * The shape of a figure's `type` -- the name boards call it by: `SCREAMING_SNAKE_CASE` starting with a capital, 3 to 32
101
- * characters. Capitals are the figure namespace; built-in scene components use lower-case kebab names, so a figure that
102
- * follows this shape cannot share a name with one.
100
+ * The shape of a figure's `type`: lower-case kebab, a letter first, 2 to 64 characters. A type is unique inside its
101
+ * namespace; boards name a figure by its full name `{namespace}/{type}` (`names.ts`), whose `/` keeps it apart from
102
+ * built-in scene components such as `conveyor` (ADR-0114).
103
103
  */
104
- export const TYPE_PATTERN = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
105
- export const TYPE_LENGTH = { min: 3, max: 32 };
104
+ export const TYPE_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
105
+ export const TYPE_LENGTH = { min: 2, max: 64 };
106
106
  /**
107
107
  * The temporary type a figure carries before anyone names it. One rule for the code that makes it and the code that
108
108
  * recognises it: the modeller makes it, the release gate and the AI tools recognise it. It passes `TYPE_PATTERN`
109
- * (`FIGURE_MTU10FWR`), so the shape check alone would not catch it.
109
+ * (`figure-mtu10fwr`), so the shape check alone would not catch it.
110
110
  */
111
111
  export function placeholderType(now = Date.now()) {
112
- return `FIGURE_${now.toString(36).toUpperCase()}`;
112
+ return `figure-${now.toString(36)}`;
113
113
  }
114
- const PLACEHOLDER_TYPE = /^FIGURE_[0-9A-Z]{8}$/;
114
+ const PLACEHOLDER_TYPE = /^figure-[0-9a-z]{8}$/;
115
115
  /** Whether a type is the temporary name given before anyone names the figure. */
116
116
  export function isPlaceholderType(type) {
117
117
  return PLACEHOLDER_TYPE.test(type);
package/dist/words.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"words.js","sourceRoot":"","sources":["../src/words.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAA;AAS5C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,CAAU,CAAA;AAGhG;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA0D,MAAM,CAAC,MAAM,CAAC;IACnG,YAAY,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;CACvC,CAAC,CAAA;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAU,CAAA;AAG9G;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAA;AAE/B;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAU,CAAA;AAG3D,2CAA2C;AAC3C,MAAM,CAAC,MAAM,UAAU,GAAgC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAA;AAEpF,mDAAmD;AACnD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAc,EAAwB,EAAE,CAAE,aAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAE5H;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,CAAA;AAIvB;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,2GAA2G;IAC3G,iBAAiB,EAAE,CAAC;IACpB,qEAAqE;IACrE,cAAc,EAAE,IAAI;IACpB,0EAA0E;IAC1E,iBAAiB,EAAE,OAAO;IAC1B;;;;OAIG;IACH,eAAe,EAAE,GAAG;IACpB;;;OAGG;IACH,gBAAgB,EAAE,EAAE;IACpB;;;;OAIG;IACH,oBAAoB,EAAE,MAAM;IAC5B,mDAAmD;IACnD,oBAAoB,EAAE,CAAC;IACvB,mGAAmG;IACnG,eAAe,EAAE,CAAC;IAClB,iDAAiD;IACjD,WAAW,EAAE,CAAC;CACN,CAAA;AAEV;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;AAEzE,iEAAiE;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAAmC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;AAE1H;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,+BAA+B,CAAA;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAW,CAAA;AAEvD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,IAAI,CAAC,GAAG,EAAE;IACtD,OAAO,UAAU,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CAAA;AACnD,CAAC;AAED,MAAM,gBAAgB,GAAG,sBAAsB,CAAA;AAE/C,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAA"}
1
+ {"version":3,"file":"words.js","sourceRoot":"","sources":["../src/words.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAA;AAS5C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,CAAU,CAAA;AAGhG;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA0D,MAAM,CAAC,MAAM,CAAC;IACnG,YAAY,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;CACvC,CAAC,CAAA;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAU,CAAA;AAG9G;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAA;AAE/B;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAU,CAAA;AAG3D,2CAA2C;AAC3C,MAAM,CAAC,MAAM,UAAU,GAAgC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAA;AAEpF,mDAAmD;AACnD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAc,EAAwB,EAAE,CAAE,aAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAE5H;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,CAAA;AAIvB;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,2GAA2G;IAC3G,iBAAiB,EAAE,CAAC;IACpB,qEAAqE;IACrE,cAAc,EAAE,IAAI;IACpB,0EAA0E;IAC1E,iBAAiB,EAAE,OAAO;IAC1B;;;;OAIG;IACH,eAAe,EAAE,GAAG;IACpB;;;OAGG;IACH,gBAAgB,EAAE,EAAE;IACpB;;;;OAIG;IACH,oBAAoB,EAAE,MAAM;IAC5B,mDAAmD;IACnD,oBAAoB,EAAE,CAAC;IACvB,mGAAmG;IACnG,eAAe,EAAE,CAAC;IAClB,iDAAiD;IACjD,WAAW,EAAE,CAAC;CACN,CAAA;AAEV;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;AAEzE,iEAAiE;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAAmC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;AAE1H;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,+BAA+B,CAAA;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAW,CAAA;AAEvD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,IAAI,CAAC,GAAG,EAAE;IACtD,OAAO,UAAU,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAA;AACrC,CAAC;AAED,MAAM,gBAAgB,GAAG,sBAAsB,CAAA;AAE/C,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAA"}
@@ -1,4 +1,4 @@
1
- # Figure v3 — 조립 관계와 반응형 제약
1
+ # Figure — 조립 관계와 반응형 제약
2
2
 
3
3
  > 상태: 아래 내용은 **폐기된 초기 초안**이다. 구현 계약으로 사용하지 않는다.
4
4
  > [재설계 상세안](design.md)이 이 문서를 대체한다. 특히 병렬 `fit/relative/face` 제약,
@@ -59,7 +59,7 @@ type Face = 'min-x' | 'max-x' | 'min-y' | 'max-y' | 'min-z' | 'max-z'
59
59
  ## 해석 순서
60
60
 
61
61
  ```text
62
- Figure v3 원본
62
+ Figure 원본
63
63
  → 부품의 기본 transform·sizing 계산
64
64
  → assembly root의 최종 상자 계산
65
65
  → assembly constraint를 위상 순서로 적용
@@ -113,7 +113,7 @@ rest pose와 인스턴스 크기 반응을 담당한다. 두 역할을 섞지
113
113
 
114
114
  1. `version: 3`은 새 저작·AI·발행의 기준 계약이다. 새 모델은 기준 상자 배치만으로
115
115
  조립 의도를 표현하지 않는다.
116
- 2. 새 Figure와 새 AI 후보는 v3 제약이 없는 상태로 저장되지 않는다. 독립 부품뿐인 단순
116
+ 2. 새 Figure와 새 AI 후보는 조립 제약이 없는 상태로 저장되지 않는다. 독립 부품뿐인 단순
117
117
  Figure는 빈 조립체 목록을 명시한다.
118
118
 
119
119
  ## 완료 기준
@@ -1,4 +1,4 @@
1
- # V3 자산 저장·복원 계약 — 실험판
1
+ # Figure 자산 저장·복원 계약 — 실험판
2
2
 
3
3
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
@@ -11,19 +11,19 @@
11
11
  - [네 대표 모델 자산 생성 예제](prototypes/asset-samples.mjs)
12
12
  - [검증 테스트](prototypes/asset.test.mjs)
13
13
 
14
- 버전은 `figure-asset-1`이다. **정식 Figure V3 전체 포맷 완료를 뜻하지 않는다.**
14
+ 버전은 `figure-asset-1`이다. **정식 Figure 전체 포맷 완료를 뜻하지 않는다.**
15
15
 
16
16
  ## 저장 항목
17
17
 
18
18
  | 항목 | 의미 |
19
19
  |---|---|
20
- | document | 기존 typed graph + capability V3 선언 |
20
+ | document | 기존 typed graph + capability 선언 |
21
21
  | designInputs | 현재 설계 입력값. 선언된 단위 그대로 저장 |
22
22
  | stateDefaults | 다시 열 때 사용할 명시적인 동작 기본값 |
23
23
  | palette | 사용한 토큰의 색상 snapshot. 미정의 토큰은 거부 |
24
24
  | appearance | source placement/member별 재질과 품질 설정 |
25
25
  | name | 자산 이름 |
26
- | occupancy | 선언한 점유 부피(`extent`: 그래프의 길이 값 셋)와 놓이는 면(`placement`). ADR-0044·0045 를 V3 로 다시 세운 것(ADR-0087 결정 3). 없으면 `inspectFigureAsset` 이 `OCCUPANCY_UNDECLARED` 를 낸다 |
26
+ | occupancy | 선언한 점유 부피(`extent`: 그래프의 길이 값 셋)와 놓이는 면(`placement`). ADR-0044·0045 를 지금 형식으로 다시 세운 것(ADR-0087 결정 3). 없으면 `inspectFigureAsset` 이 `OCCUPANCY_UNDECLARED` 를 낸다 |
27
27
  | document.capabilities.names | 도형 수준 능력 이름. `FIGURE_CAPABILITIES` 목록 그대로 검사한다(ADR-0051 ④) |
28
28
 
29
29
  메시·계산된 pose·과거 성공 판정은 저장하지 않는다. 다시 로드하면 선언에서 재계산한다. 이 프로토타입은 팔레트 색상을 고정 snapshot으로 저장한다. 제품 공통 테마를 따라갈지 자산 색상을 유지할지는 별도 정책이 필요하다. 조명·환경맵·카메라는 이 계약에 포함되지 않아 모든 화면의 픽셀 동일성을 보장하지 않는다.
@@ -42,7 +42,7 @@ appearance는 모든 `place@1`/`member@1`에 정확히 하나씩 필요하다.
42
42
 
43
43
  원기둥 분할 수는 현재 지원 preset으로 명시 저장한다. 사용자에게 분할 수 직접 입력 UI를 추가하지 않았다. 다른 provider에 임의의 segments를 붙이는 것은 거부한다. 재질은 token/preset/transparent/emissive 범위를 지원하며 미지원 필드를 조용히 버리지 않고 거부한다.
44
44
 
45
- 부품에 붙이는 capability 메타데이터는 정본에 자리를 두지 않는다(2026-09-23). 자리만 남겨 두면 검증된 binding과 구별되지 않기 때문이다. `slot`을 `seat`/`grip`으로 자동 해석하지도 않는다. 이 의미를 V3로 가져오려면 검증되는 binding으로 다시 저작한다.
45
+ 부품에 붙이는 capability 메타데이터는 정본에 자리를 두지 않는다(2026-09-23). 자리만 남겨 두면 검증된 binding과 구별되지 않기 때문이다. `slot`을 `seat`/`grip`으로 자동 해석하지도 않는다. 이 의미를 지금 형식으로 가져오려면 검증되는 binding으로 다시 저작한다.
46
46
 
47
47
  ## 검증 결과
48
48
 
@@ -59,10 +59,10 @@ appearance는 모든 `place@1`/`member@1`에 정확히 하나씩 필요하다.
59
59
 
60
60
  ## 남은 제품화 범위
61
61
 
62
- - 예제 생성기는 V3로 이미 재저작한 모델을 포장한다. 범용 마이그레이터가 아니다.
63
- - 원본에 없는 기능을 복원했다고 주장하지 않는다. 기존 자산은 V3로 재작성하며, 실제 데이터 교체 전에 대상과 복구본을 확인한다.
62
+ - 예제 생성기는 지금 형식으로 이미 재저작한 모델을 포장한다. 범용 마이그레이터가 아니다.
63
+ - 원본에 없는 기능을 복원했다고 주장하지 않는다. 기존 자산은 지금 형식으로 재작성하며, 실제 데이터 교체 전에 대상과 복구본을 확인한다.
64
64
  - 네 대표 모델을 넘는 provider/material 확장, 입력 라벨/저작 메타데이터 등은 정식 포맷에서 추가 정의해야 한다.
65
65
  - 파일 시스템 원자적 교체·권한·DB revision 충돌·업로드/다운로드 API는 없다. 함수는 문자열을 반환하며 제품 저장소에 직접 쓰지 않는다.
66
66
  - 실제 속성창·AI-dock·새 모델/다른 모델 전환·재접속은 통합 테스트가 남아 있다.
67
67
 
68
- 저장된 자산을 공통 편집 세션으로 여는 연결과 격리 UI 검증은 [편집 화면 연결 검증](editor-integration.md)에 기록했다. 다음 게이트는 실제 제품의 V3 전용 편집 경로와 저장 API 연결이다. 프로토타입 테스트 수를 제품 배포 완료 여부로 사용하지 않는다.
68
+ 저장된 자산을 공통 편집 세션으로 여는 연결과 격리 UI 검증은 [편집 화면 연결 검증](editor-integration.md)에 기록했다. 다음 게이트는 실제 제품의 편집 경로와 저장 API 연결이다. 프로토타입 테스트 수를 제품 배포 완료 여부로 사용하지 않는다.
@@ -6,7 +6,7 @@
6
6
 
7
7
  [입력 세션](../src/authoring-session.ts)은 design/state 값 편집을 담당한다. [workspace](../src/editor-workspace.ts)는 상자 추가와 입력 편집을 같은 50단계 undo/redo 이력으로 관리한다. [검증 테스트](prototypes/authoring-session.test.mjs)는 정식 소스 구현을 호출한다. 격리 UI에는 새 Figure·상자 추가·undo/redo 버튼이 연결되어 있다. 제품 AI-dock·일반 그래프 재저작·삭제·재질 편집은 아직 미완료다.
8
8
 
9
- 세션은 V3 문서와 초기 입력을 받아 동일 compiler로 검증한다. UI/AI 모두 아래 같은 요청을 사용한다.
9
+ 세션은 Figure 문서와 초기 입력을 받아 동일 compiler로 검증한다. UI/AI 모두 아래 같은 요청을 사용한다.
10
10
 
11
11
  ```json
12
12
  {
@@ -54,4 +54,4 @@ read/preview/apply 반환값과 초기 선언은 내부 상태와 분리한다.
54
54
 
55
55
  세션은 메모리에서 동작한다. 자산 저장 계약과 설계 값/일시적 동작의 분리 정책은 구현했고, 격리 HTTP 파일 저장·복원·충돌 검증도 통과했다. 제품 DB·재접속·다중 사용자 편집, 제품 UI의 preview 승인과 AI 명령 변환·권한 검사는 남아 있다.
56
56
 
57
- 다음 제품화 단계는 실제 모델러·AI·저장·렌더러를 이 공통 V3 경로로 전환하는 것이다. 완료된 저장 계약을 다시 설계하는 단계가 아니다.
57
+ 다음 제품화 단계는 실제 모델러·AI·저장·렌더러를 이 공통 경로로 전환하는 것이다. 완료된 저장 계약을 다시 설계하는 단계가 아니다.
@@ -104,6 +104,6 @@ region은 의미상 허용/검사 영역이다. 표시용 가이드가 될 수
104
104
  4. 지원하는 평면 feature만 허용한다: box의 6면, roundedBox의 위/아래, cylinder의 start/end.
105
105
  5. feature 중심과 바깥쪽 법선을 실제 placement 변환으로 계산한다. 기존 feature frame 축은 provider 축이므로 법선과 혼동하지 않는다.
106
106
 
107
- 반환된 `verified-planar-surface`는 **출처가 검증된 평면이라는 뜻**이지 payload와 접촉했다는 뜻이 아니다. 정점/면 영역 전체, 허용 오차, 하중 지지, 충돌 여부는 별도 검사다. curved feature, portal 등의 아직 정의되지 않은 경우를 가짜 평면으로 추정하지 않고 거부한다. 단일 repeat의 선택된 평면은 V3 계약에서 지원한다.
107
+ 반환된 `verified-planar-surface`는 **출처가 검증된 평면이라는 뜻**이지 payload와 접촉했다는 뜻이 아니다. 정점/면 영역 전체, 허용 오차, 하중 지지, 충돌 여부는 별도 검사다. curved feature, portal 등의 아직 정의되지 않은 경우를 가짜 평면으로 추정하지 않고 거부한다. 단일 repeat의 선택된 평면은 이 계약에서 지원한다.
108
108
 
109
109
  [직렬화 계약 및 테스트 결과](document-contract.md)를 함께 참조한다.
@@ -1,4 +1,4 @@
1
- # 공통 v3 실행 커널 실험
1
+ # 공통 실행 커널 실험
2
2
 
3
3
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
@@ -109,7 +109,7 @@ rect는 box로 축약한 **배치 검증용 proxy**다. 모서리 외형 보존
109
109
  2. 반복 위치와 개별 형상 운동의 순서는 명세에 반드시 들어가야 한다.
110
110
  3. geometry도 상태를 입력받아야 한다. 강체 frame에만 상태를 넣는 r2는 부족하다.
111
111
  4. 단일 상속으로 포크리프트를 표현할 수 있지만 기존 flat 채널의 자동 변환은 별도 문제다.
112
- 5. **이 실험으로 v3 설계 완성을 선언할 수 없다.** proxy/부분 모델을 전체 fidelity 변환으로
112
+ 5. **이 실험으로 Figure 설계 완성을 선언할 수 없다.** proxy/부분 모델을 전체 fidelity 변환으로
113
113
  확대하고, feature/단위/반복 subtree/참조 정책을 정리한 뒤 렌더러 비교가 필요하다.
114
114
 
115
115
  다음 검증 우선순위는 geometry feature와 반복 subtree를 공통 계약에 포함하는 것이다.
@@ -4,7 +4,7 @@
4
4
  코드와 공개 계약을 검토하고 `npm test` 및 별도 경계 사례를 실행했다.
5
5
  런타임 코드를 변경하거나 발행하지 않았다. 설치된 제품 및 npm 배포 상태는 이번 점검 범위가 아니다.
6
6
 
7
- ## 해결 현황 (2026-10-04, 미발행)
7
+ ## 해결 현황 (2026-10-04, figure-model 0.3.3 · things-scene 10.1.72 발행)
8
8
 
9
9
  F1~F4를 고쳤다. 항목마다 기존 코드에서 실패하는 회귀 시험을 먼저 넣었고, 고친 뒤 `npm test`(타입 검사와
10
10
  725개 시험)와 build가 통과한다. 재현 스크립트는 이제 네 항목 모두 거절 또는 정상 결과를 출력한다.
@@ -88,6 +88,155 @@ API 호환성 영향:
88
88
  - 복사 구조 재설계(대규모 resize 최적화)는 별도 과제다. 결과 소유권 결함을 다시 열지 않고, 브라우저 전체 프레임의
89
89
  중앙값·p95를 기준으로 진행한다.
90
90
 
91
+ ### 제자리 동결 후보의 측정 결과 (2026-10-04): 효과 미확인, 채택하지 않음
92
+
93
+ 시험한 설계는 다음과 같다. 어떤 노드도 읽지 않는 행(롤러 컨베이어의 롤러 행)은 사본·경로·자세를 행 연산이 새로
94
+ 만들고 이후 내부에서 다시 읽지 않는다. 따라서 이 행의 슬롯은 형상처럼 제자리에서 동결하고 복사하지 않는다.
95
+ 배치가 만드는 body 껍데기(`{ id, ...g }`)도 결과만 보유하므로 제자리에서 동결하고, 담긴 자세는 동결 사본으로 바꾼다.
96
+ 행이 읽는 자세, 배치 값, 구성원 같은 내부 계산 객체는 동결하지 않고 지금처럼 복사한다. terminal repeat의 pose step은
97
+ 읽히지 않는 행의 항목을 읽지 않으므로 동결 자세를 읽지 않는다.
98
+
99
+ - 정확성: figure-model 시험 728개, things-scene figure 시험 74개(형제 소스 연결)가 후보에서도 통과했다.
100
+ 공유 사본을 동결하지 않는 결함을 심으면 소유권 시험 5개가 실패했다.
101
+ - 사본 수: 롤러 컨베이어 크기 변경 한 번에 `publicOf` 사본이 약 100개에서 35개(자세 17, 배치 값 16, 배치 1, 중심 목록 1)로
102
+ 줄었다. 동결 횟수는 391회로 같다. 행 항목을 복사하던 일이 같은 수의 제자리 동결로 바뀌었을 뿐이며,
103
+ 숫자 배열 동결이 값을 박싱하는 비용도 그대로 남는다.
104
+ - 커널(Node, 크기 변경 step, 인스턴스당, 번갈아 3회): 51~64 → 50~58 µs, 약 5~10% 감소.
105
+ - 브라우저 전체 프레임(`things-scene/test/browser/check-figure-update-cost.mjs`, Apple GPU, 인스턴스 60개, merge on,
106
+ 워밍업 60, 600프레임, F1 적용판과 후보를 번갈아 3회. 표의 값은 frame 중앙값(p95) ms, 측정 해상도 0.1 ms):
107
+
108
+ | 장면 | F1 적용판 | 후보 |
109
+ | ------------------------------------ | ------------------------------------ | ---------------------------------- |
110
+ | 컨베이어 크기 끌기(매 프레임 evaluate) | 8.2 (10.7) · 6.9 (8.3) · 7.7 (10.3) | 7.3 (8.3) · 7.6 (8.9) · 7.5 (8.7) |
111
+ | 컨베이어 회전(pose step만) | 3.0 (4.3) · 5.0 (6.7) · 3.9 (5.3) | 3.9 (6.1) · 5.0 (6.5) · 3.8 (4.7) |
112
+ | 문+램프 flag 교차(매 프레임 evaluate) | 2.6 (4.1) · 3.8 (5.6) · 3.3 (4.0) | 3.7 (5.4) · 3.0 (4.1) · 2.9 (4.4) |
113
+
114
+ 후보의 중앙값은 F1 적용판의 회차 간 변동 범위 안에 있다. p95는 회차에 따라 줄기도 하고 늘기도 했다(크기 끌기
115
+ 10.7→8.3, 회전 4.3→6.1, flag 4.1→5.4). 개선과 악화가 섞여 있어 일관된 성능 차이를 확인하지 못했다. 크기 끌기 장면의
116
+ rig `update`(평가 포함)는 5.3~5.8 대 5.5~5.7 ms로 차이가 없다. 커널이 5~10% 줄었어도 rig와 전체 프레임의 개선이
117
+ 확인되지 않았으므로 채택 기준을 충족하지 못했다. 판정은 「효과 미확인」이며 채택하지 않았다. F1 정확성 수정은 유지한다.
118
+ 0.3.2의 값(크기 끌기 4.05 ms, p95 6.0, Node CPU rig 측정)은 참고값으로만 남긴다. 측정 방식이 달라 위 표와 직접
119
+ 비교하지 않는다.
120
+
121
+ 크기 변경 프로필(후보 기준, self time)은 `frozen` 17%, `step` 12%, `publicOf` 11%, `finite` 10%, GC 5%였다.
122
+ 사본 수를 줄이는 것만으로는 충분하지 않았다. 동결·평가·rig·렌더 비용이 남는다. 숫자 배열 동결이 다음 후보라는 것은
123
+ 프로필에서 얻은 단서이고, 공개 자세 표현을 바꾸면 빨라진다는 결론은 아니다. 크기 끌기 프레임 7~8 ms 가운데 커널은
124
+ 약 3 ms이고, rig 몫이 2.2~2.7 ms, 렌더가 1.4~1.7 ms다. 다음 순서는 공개 API 변경보다 rig의 크기 변경 처리 비용 분해다.
125
+
126
+ 이번에 남긴 것은 다음과 같다.
127
+
128
+ - `src/result-ownership.test.ts`의 시험 2개. 인스턴스가 상태 변경, 크기 변경, pose step을 거친 뒤에도 전체 평가 결과에
129
+ 동결된 객체가 없음을 확인한다. 또 크기 변경 직후 pose step이 새 구조의 행을 모두 그리고 전체 평가와 같은 자세를
130
+ 내며, 행이 읽는 배치·자세가 비동결 내부 객체임을 확인한다. 두 시험 모두 현재 코드에서 통과하고, 슬롯 동결 결함과
131
+ 전체 평가 동결 결함을 심으면 실패한다.
132
+ - things-scene 측정 스크립트의 `gate` 종류. 문+램프 Figure를 스크립트 안에서 만들고, flag가 매 프레임 문턱을 넘게 한다.
133
+
134
+ ### rig 크기 변경 비용 분해와 형상별 키 캐시 (2026-10-05): 효과 미확인, 채택하지 않음
135
+
136
+ 분해(`check-figure-update-cost.mjs`의 `BREAKDOWN=1`, 컨베이어 60대, 프레임당 60대 합계 중앙값)에서 크기 변경 프레임의
137
+ rig `update` 약 5 ms는 커널 3.0~3.3 ms, 배치 계획 0.66~0.74 ms, 병합 묶음 0.78~0.97 ms, 단독 mesh·행 0.28~0.32 ms,
138
+ `dress` 0.19~0.23 ms로 나뉜다. mesh와 instanced mesh는 새로 만들어지지 않는다. 매 프레임 새로 그리는 geometry는 60대가
139
+ 함께 쓰는 병합 geometry 3개이고, 행 버퍼 60개가 다시 올라간다. CPU 쪽 바이트는 프레임당 약 149~152 KB다. 렌더 시간은
140
+ 회전만 하는 프레임보다 길지 않았다. 현재 측정에서 GPU 업로드가 추가 병목이라는 근거는 찾지 못했다. 업로드 개수가
141
+ 같다고 바이트와 드라이버 비용까지 같다는 뜻은 아니며, 드라이버 쪽 비용은 재지 않았다. CPU 프로필에서 반복되는 일은
142
+ 모든 인스턴스의 모든 body에 대해 매 프레임 다시 만드는 문자열 키였다(batch signature, geometry 키).
143
+
144
+ 시험한 후보는 형상 부분의 키를 형상 객체마다 한 번만 계산해 `WeakMap`에 두는 것이다.
145
+
146
+ - figure-model `render-batches.ts`의 signature와 things-scene `figureGeometryKeyOf`에 적용했다. 공개 API는 바뀌지 않는다.
147
+ - 형상 부분만 캐시하고 segments·재질·표시 여부는 매번 읽는다.
148
+ - 끝까지 동결된 형상만 캐시한다. 가변 형상과 겉만 동결된 형상은 매번 계산한다.
149
+ - 값은 문자열이므로 형상이나 GPU 자원을 붙잡지 않는다.
150
+ - 시험: figure-model 3개, things-scene 3개(`test/figure-geometry-key.check.js`). 무조건 캐시, 얕은 동결 검사, 전체 signature를
151
+ 형상으로 캐시하는 결함을 심으면 실패한다. 이 시험들은 현재 코드에서도 통과하므로 남겨 두었다.
152
+
153
+ 브라우저 A/B(F1 적용판과 후보를 번갈아 3회, 인스턴스 60개, merge on, 워밍업 60, 600프레임, frame 중앙값(p95) ms).
154
+ 끌기는 매 프레임 새 크기이고 롤러 행이 24개에서 27개로 늘어난다.
155
+
156
+ | 장면 | F1 적용판 | 후보 |
157
+ | ---------------------------- | -------------------------------- | --------------------------------- |
158
+ | 컨베이어 크기 끌기(두 크기 교대) | 7.27 (9.39) · 6.63 (8.11) · 7.44 (8.99) | 7.11 (8.63) · 6.72 (8.42) · 7.79 (10.02) |
159
+ | 컨베이어 끌기(행 개수 변화) | 7.31 (9.03) · 6.74 (8.59) · 7.35 (9.17) | 6.72 (8.78) · 6.78 (8.29) · 8.20 (10.45) |
160
+ | 컨베이어 회전(pose step만) | 4.01 (4.76) · 3.61 (5.16) · 5.75 (7.39) | 4.44 (5.57) · 3.82 (5.74) · 4.39 (5.77) |
161
+ | 문+램프 flag 교차 | 2.92 (4.36) · 2.76 (4.37) · 3.93 (5.18) | 3.25 (4.92) · 4.38 (6.19) · 3.24 (4.48) |
162
+
163
+ 단계 분해(각 판 1회라 잠정값)에서 배치 계획은 0.68~0.72 → 0.48~0.49 ms로 줄었다. 병합 묶음(0.88~0.93 → 0.91~0.95 ms)과 업로드 바이트는
164
+ 같았다. 전체 프레임의 중앙값과 p95는 회차마다 개선과 악화가 섞여 있어 일관된 차이를 확인하지 못했다. 판정은
165
+ 「효과 미확인」이며 채택하지 않았다. 문+램프 장면은 batch가 없어 이 변경과 무관하며, 회차 간 변동만 보여 준다.
166
+
167
+ 측정 스크립트에 함께 남긴 것은 다음과 같다.
168
+
169
+ - `BREAKDOWN=1`: rig 단계별 시간, 새 geometry·mesh·업로드 버퍼 수와 CPU 쪽 바이트.
170
+ - `PROFILE=1`: 페이지 CPU 프로필.
171
+ - `drag` 장면.
172
+ - 시계 해상도를 µs로 올리려고 페이지를 cross-origin isolated로 띄운다.
173
+ - 행렬 수 열은 이제 매 프레임 mesh를 다시 찾는다. 개수가 늘어난 행이나 새 mesh는 그리는 사본 전부를 쓴 것으로 센다.
174
+ 이전에는 처음 찾은 mesh만 비교해서 행이 커지면 0으로 나왔다.
175
+
176
+ ### 병합 geometry 재생성 분해와 부품 geometry 재사용 (2026-10-05): 채택 보류
177
+
178
+ 측정 방식부터 바꿨다. 판을 하나씩 따로 띄워 번갈아 재는 방식은 같은 판끼리의 A/A에서 짝지은 frame 중앙값 차이가
179
+ 최대 ±1.9 ms였다(ABBA 4쌍, 다른 세션이 돌아 부하 평균 약 5). 그래서 두 판을 한 페이지에 함께 띄우고 프레임 블록을
180
+ 무작위 순서로 번갈아 도는 `things-scene/test/browser/check-figure-ab.mjs`를 만들었다. 두 판은 번들, 은행, 렌더러를
181
+ 따로 갖는다. things-scene 소스 교체는 작업 트리를 건드리지 않고 rollup에서 overlay 파일로 한다. 이 방식의 A/A
182
+ (블록 150개×10프레임, 2회)에서 블록 차이의 중앙값은 ±0.06 ms 이내, 양쪽 frame 중앙값 차이는 0.07 ms 이내였다.
183
+
184
+ frame에는 상태·크기 쓰기, rig `update`, 렌더와 1픽셀 읽기가 들어간다. 측정 스크립트의 `kernel` 열(따로 둔 evaluator)은
185
+ frame에 들어가지 않는다. 병합 geometry 생성은 `update` 안의 `drawMerged`에서 일어나고, GPU 업로드는 렌더에서 일어난다.
186
+ 따라서 frame 안에서 커널, geometry 생성, 렌더가 겹쳐 세어지지 않는다. `BREAKDOWN=1`의 단계 시간은 모두 `update` 안에
187
+ 포함된 부분이다.
188
+
189
+ 분해(Node, 롤러 컨베이어, 단위는 아래에 적음):
190
+
191
+ - 60대가 함께 쓰는 병합 geometry는 그룹 3개이고, 크기마다 그룹당 한 번만 만들어진다. 두 크기 교대와 매 프레임 새 크기
192
+ 모두 프레임마다 3개가 만들어진다. 두 크기 교대에서는 이전 크기의 마지막 사용자가 놓는 순간 entry가 해제되어 다음
193
+ 프레임에 다시 만들어진다. 이는 캐시 수명으로 줄일 수 있다. 매 프레임 새 크기에서는 생성 비용 자체를 줄여야 한다.
194
+ - 새 크기 한 번의 생성, 세 그룹 합계(= 프레임당): 228~248 µs. 이 가운데 부품 형상의 삼각형화가 160~169 µs, bounds
195
+ 계산이 34~35 µs, 정점 변환·복사·법선 계산이 17~20 µs, 버퍼 생성이 5 µs다. 같은 크기 은행 조회는 rig 하나당 6~8 µs
196
+ (형상 문자열 키 4.5, 자세 숫자 1.5)이고 60대가 매 프레임 한다.
197
+ - 크기 변경 뒤에도 같은 형상 객체인 부품이 16개 중 11개다. 그런데도 다시 삼각형화된다. 병합 geometry는 정점 사본을
198
+ 가지므로 생성이 끝나면 부품 geometry를 놓는다. 부품을 따로 그리는 mesh가 없으면 사용자가 0이 되어 바로 dispose된다.
199
+ 이것은 현재 참조 수 규칙에 따른 정상 해제다.
200
+
201
+ 후보는 참조 수명을 늘리는 최적화다. 병합 entry가 자기 부품 geometry를 entry의 수명 동안 잡고, entry를 해제할 때 놓는다.
202
+
203
+ - rig는 새 묶음을 먼저 얻고 나서 이전 묶음을 놓는다. 따라서 형상이 같은 부품은 키로 재사용되고, 형상이 바뀐 부품은
204
+ 키가 달라 새로 만들어진다.
205
+ - 부품 바이트는 여러 entry가 공유해도 한 번만 세어 은행 상한에 넣는다. 새·이전 entry가 함께 있는 순간에도 상한이
206
+ 적용된다. 생성이 거절되면 잡았던 부품을 모두 돌려준다.
207
+ - 시험 4개를 만들었다. 같은 부품 geometry 재사용과 병합 없이 그린 것과의 일치, 공유 바이트 한 번 계산과 정확한 차감,
208
+ 공존 순간의 상한과 거절 시 반환, 반복 크기 변경·생성·최종 dispose 뒤 회수다. 처음 셋은 HEAD에서 실패하고 후보에서
209
+ 통과한다. 해제 누락, 거절 시 미반환, 공유 바이트 중복 계산 결함을 심으면 각각 실패한다.
210
+ - Node에서 새 크기 생성은 세 그룹 합계 248 → 150 µs다(그룹별 142/30/76 → 96/22/32 µs).
211
+
212
+ 브라우저(한 페이지 교차, 인스턴스 60개, 블록 150개×10프레임, frame 중앙값(p95) ms, B−A는 블록 차이의 중앙값):
213
+
214
+ | 장면 | 회차 1 | 회차 2 | 회차 3 | 회차 4 |
215
+ | ------------------------ | ------------------------------- | ------------------------------- | ------------------------------- | -------------------------------- |
216
+ | 크기 교대 A→B | 7.43 (9.49) → 7.26 (9.23), −0.16 | 6.84 (8.77) → 6.74 (8.57), −0.13 | 6.92 (8.81) → 6.87 (9.10), −0.06 | 8.22 (11.03) → 8.33 (11.19), +0.08 |
217
+ | 끌기(행 개수 변화) A→B | 8.36 (11.24) → 8.19 (11.04), −0.21 | 7.16 (8.50) → 7.10 (8.47), −0.08 | 7.06 (8.55) → 6.89 (8.52), −0.14 | 7.97 (10.35) → 7.94 (10.35), −0.08 |
218
+ | 회전(pose step만) | +0.02 | +0.07 | (생략) | (생략) |
219
+ | 문+램프 flag | +0.00 | −0.05 | +0.05 | −0.00 |
220
+
221
+ - 끌기: 4회 모두 중앙값이 0.08~0.21 ms 줄었다. A/A 폭(±0.06 ms)보다 크고, p95는 악화되지 않았다(0~−0.20 ms).
222
+ Node 추정(약 0.1 ms)과도 맞는다.
223
+ - 크기 교대: 중앙값이 −0.16, −0.13, −0.06, +0.08로 섞였고, p95는 2회에서 악화됐다(+0.29, +0.16 ms).
224
+ - 메모리(인스턴스마다 크기가 다른 distinct, 컨베이어 500대, 2회 같은 값): heap 67.7 → 74.6 MB(+6.9 MB), 은행 바이트
225
+ 28.56 → 34.22 MB(+20%). 생성 시간은 446~447 → 405~410 ms로 줄었다. 모두 dispose한 뒤 남는 양은 1.9 MB로 같았다.
226
+
227
+ 판정은 채택 보류다. 끌기에서는 개선이 일관되게 보였다. 그러나 크기 교대의 p95가 악화된 회차가 있고, 메모리가 은행
228
+ 기준 20% 늘어난다. 소스는 HEAD로 두었다. 남긴 것은 반복 크기 변경·생성·최종 dispose 뒤 회수 시험(HEAD에서 통과)과
229
+ `check-figure-ab.mjs`다. 후보 전용 시험 3개는 HEAD에서 실패하므로 커밋하지 않았다. 다시 시도할 때는 위 조건으로 같은
230
+ 시험을 먼저 넣는다.
231
+
232
+ 갱신 구간 동안만 부품을 잡는 후보(things-scene `docs/plans/figure-merged-part-renewal.md`)도 같은 날 시험했고 채택하지
233
+ 않았다. Node에서 새 크기 생성은 248 → 152 µs로 줄었지만, 한 페이지 교차 A/B의 frame 중앙값과 p95 차이가 같은 조건
234
+ A/A 폭 안에 있었다. 위 장기 보유 후보의 끌기 감소도 측정 변동이었을 가능성을 배제할 수 없다. 자세한 수치는 그 문서에 있다.
235
+
236
+ 측정 조건 기록: A/A(따로 띄우는 방식) 도중 `test/figure-merge.check.js`에 시험을 추가했다. 측정 스크립트는 실행마다
237
+ `src`를 rollup으로 한 번 묶으며, 시험 파일은 번들에 들어가지 않는다. 파일 감시나 자동 재빌드도 쓰지 않는다. 그래서
238
+ 측정 조건은 바뀌지 않았다고 판단한다.
239
+
91
240
  ## 종합 판단
92
241
 
93
242
  이 패키지는 **이름 있는 부품의 치수·자세·반복·연결을 선언하고, 같은 정의를 저작·검사·씬에서 소비하는
@@ -1,4 +1,4 @@
1
- # Figure Model V3 핵심 의미론 기준안 — r3
1
+ # Figure Model 핵심 의미론 기준안 — r3
2
2
 
3
3
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
@@ -271,7 +271,7 @@ AI의 자유 텍스트가 geometry나 외부 바인딩을 직접 바꾸지 않
271
271
  정점 수, draw call, resolve/compile 시간, 캐시 적중과 메모리를 실제 규모에서 측정한다.
272
272
  수치 없는 '고성능 보장'은 하지 않는다.
273
273
 
274
- 제품은 V3 단일 실행 체계를 쓴다. 기존 자산은 V3 재작성으로 교체한다.
274
+ 제품은 단일 실행 체계를 쓴다. 기존 자산은 지금 형식으로 다시 작성해 교체한다.
275
275
  복구용 원본 보관은 데이터 교체의 안전 절차이지 모델 설계 제약이 아니다.
276
276
  현재 좌표를 고정한 변환과 반응형 의도를 복원한 재작성을 같은 성공으로 보고하지 않는다.
277
277
 
package/docs/cutover.md CHANGED
@@ -1,10 +1,10 @@
1
- # V3 단일 체계 전환 — 작업 기준
1
+ # 단일 체계 전환 — 작업 기준
2
2
 
3
3
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
5
- 사용자 결정: 제품은 V3 하나를 쓴다. V3의 단순성·일관성·저작성·품질을 우선하며, 버전별 편집 경로는 두지 않는다.
5
+ 사용자 결정: 제품은 한 가지 형식만 쓴다. 그 형식의 단순성·일관성·저작성·품질을 우선하며, 버전별 편집 경로는 두지 않는다.
6
6
 
7
- 제품 모델러·AI·저장·렌더러는 V3 하나를 기준으로 한다. 기존 자산은 V3로 재작성한다. 기존 데이터의 파괴적 교체는 대상 확인과 복구본 확보 후 별도로 수행한다.
7
+ 제품 모델러·AI·저장·렌더러는 이 형식 하나를 기준으로 한다. 기존 자산은 지금 형식으로 재작성한다. 기존 데이터의 파괴적 교체는 대상 확인과 복구본 확보 후 별도로 수행한다.
8
8
 
9
9
  V2와 V1은 2026-09-26 코드와 명세에서 제거했다. ADR-0087의 전환은 제거로 마쳤다.
10
10
 
@@ -26,4 +26,4 @@ V2와 V1은 2026-09-26 코드와 명세에서 제거했다. ADR-0087의 전환
26
26
 
27
27
  제품의 버튼 연결, 다른 primitive 생성, 관계 편집, 실제 DB 저장·렌더러 전환은 아직 완료하지 않았다. 위치와 크기를 바꿔 바닥을 유지하려면 두 입력을 함께 편집해야 한다. 이번 상자 생성은 조립 관계를 자동 추론하지 않는다.
28
28
 
29
- 이제 다음 제품 작업은 V3 생성·편집 명령을 실제 모델러의 사용자 동작에 연결하는 것이다. 호환 분기 추가는 하지 않는다. 패키지 설치·배포는 소스 구현과 구별해 확인한다.
29
+ 이제 다음 제품 작업은 Figure 생성·편집 명령을 실제 모델러의 사용자 동작에 연결하는 것이다. 호환 분기 추가는 하지 않는다. 패키지 설치·배포는 소스 구현과 구별해 확인한다.
@@ -1,10 +1,10 @@
1
- # V3 그래프·capability 직렬화 계약 — 실험판
1
+ # Figure 그래프·capability 직렬화 계약 — 실험판
2
2
 
3
3
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
5
5
  ## 범위와 상태
6
6
 
7
- 실험 그래프와 capability 선언을 저장하고 재로드해 의미 검증하는 계약을 구현했다. **전체 Figure V3 제품 파일 포맷 확정이 아니다.** 현재 전체 모델 예제의 재질·분할 수·외부 capability 메타데이터 일부는 어댑터가 공급한다. 그 데이터까지 이 포맷이 저장한다고 주장하지 않는다. 제품 DB·서버·UI는 변경하지 않았다.
7
+ 실험 그래프와 capability 선언을 저장하고 재로드해 의미 검증하는 계약을 구현했다. **전체 Figure 제품 파일 포맷 확정이 아니다.** 현재 전체 모델 예제의 재질·분할 수·외부 capability 메타데이터 일부는 어댑터가 공급한다. 그 데이터까지 이 포맷이 저장한다고 주장하지 않는다. 제품 DB·서버·UI는 변경하지 않았다.
8
8
 
9
9
  후속 [자산 저장 envelope](asset-persistence.md)는 이 document를 감싸 설계 입력·동작 기본값·재질·팔레트·분할 품질을 함께 저장한다. document 단독 포맷과 자산 envelope의 지원 범위를 혼동하지 않는다.
10
10
 
@@ -32,7 +32,7 @@ JSON Schema는 필드 구조·자료형·기본 enum·버전을 검사한다. op
32
32
 
33
33
  ## 손실·오류 정책
34
34
 
35
- - 알 수 없는 문서/계약 버전과 추가 필드를 거부한다. 현재 capability V3는 transform 또는 표면 참조 pose를 허용한다. V1/V2를 추측 변환하지 않는다.
35
+ - 알 수 없는 문서/계약 버전과 추가 필드를 거부한다. 현재 capability 선언은 transform 또는 표면 참조 pose를 허용한다. V1/V2를 추측 변환하지 않는다.
36
36
  - JSON 키 중복은 마지막 값으로 덮지 않고 거부한다. Unicode escape로 같은 키가 표현된 경우도 포함한다.
37
37
  - 잘린 JSON, 비유한 수, undefined, 함수, Date, 순환, sparse array, accessor·숨겨진 속성 등 JSON으로 손실되는 입력을 거부한다.
38
38
  - 실험 자원 제한: 1MiB UTF-8, 객체 깊이64, 그래프 node 8192(`FIGURE_DOCUMENT_NODE_LIMIT`, 2026-09-29 판정 — shape-contract Q10: 충분히 크게. 실제로는 1MiB 가 먼저 걸린다).
@@ -4,7 +4,7 @@
4
4
 
5
5
  > **2026-09-26:** `portal-profile@1`(좌표 여덟)은 `portal-profile@2`로 바뀌었다. 입력은 폭 · 높이 · 깊이 · 기둥 두께 · 인방 두께의 다섯이고, 좌우로 가운데, 바닥에 서며, 좌표 여덟은 이 값에서 나온다. 앞 셋이 상자와 같아 크기를 따를 수 있다. 아래는 @1 때의 기록이다.
6
6
 
7
- 상태: 독립 V3 실험. 제품/DB/원본 시드 수정 없음.
7
+ 상태: 독립 Figure 실험. 제품/DB/원본 시드 수정 없음.
8
8
  `operato-application/packages/operato-figure/server/seed/figure-samples.json`의
9
9
  DRY_ROOM portal-in/out과 lamp-in/out을 읽었다. 서버에서 편집된 revision은 검사하지 않았다.
10
10
  shell/readout을 포함한 드라이룸 전체 변환도 아니다.
@@ -1,10 +1,10 @@
1
- # V3 편집 화면 연결 검증 — 실험판
1
+ # Figure 편집 화면 연결 검증 — 실험판
2
2
 
3
3
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
5
5
  ## 완료 범위
6
6
 
7
- 저장된 V3 자산을 공통 편집 세션으로 열고, 입력 변경을 평가된 3D 장면으로 전달하는 연결 계층을 구현했다. **제품 모델러·서버·DB에는 아직 연결하지 않았다.**
7
+ 저장된 Figure 자산을 공통 편집 세션으로 열고, 입력 변경을 평가된 3D 장면으로 전달하는 연결 계층을 구현했다. **제품 모델러·서버·DB에는 아직 연결하지 않았다.**
8
8
 
9
9
  - 연결 계층: [editor-workspace.ts](../src/editor-workspace.ts) — 실험 mjs는 re-export만 유지
10
10
  - 계약 검증: [editor-workspace.test.mjs](prototypes/editor-workspace.test.mjs)
@@ -31,7 +31,7 @@
31
31
 
32
32
  ## 실제 확인 결과
33
33
 
34
- 2026-09-21, 전체 `v3-*.test.mjs` 138개 통과(실패 0). 이번 workspace 테스트 4개 포함. 별도로 실제 Chrome/Three.js 격리 화면에서 다음 경로를 검증했다.
34
+ 2026-09-21, 전체 `docs/prototypes/*.test.mjs` 138개 통과(실패 0). 이번 workspace 테스트 4개 포함. 별도로 실제 Chrome/Three.js 격리 화면에서 다음 경로를 검증했다.
35
35
 
36
36
  1. 포크리프트 20개 메시 열기.
37
37
  2. 포크 길이 850 → 1275mm 변경, 렌더링 입력의 실제 형상 치수 확인.
@@ -47,7 +47,7 @@
47
47
 
48
48
  현재 figure-ui의 `client/modeller/figure-source.ts`는 장면 파트를 저장용 이전 형식 source로 변환한다. `figure-inspector.ts`와 `figure-modeller-page.ts`의 update-part/update-draft 경로도 이전 형식의 draft/parts 중심이다. graph를 이 경로의 `parts`로 가장해 전달하면 원본이 이중화된다.
49
49
 
50
- 제품 모델러·저장·AI·렌더러를 V3 단일 경로로 전환한다. 기존 자산은 V3로 재작성한다. 호환 분기는 만들지 않는다. 제품에서는 src에서 빌드한 공용 API를 사용한다.
50
+ 제품 모델러·저장·AI·렌더러를 단일 경로로 전환한다. 기존 자산은 지금 형식으로 재작성한다. 호환 분기는 만들지 않는다. 제품에서는 src에서 빌드한 공용 API를 사용한다.
51
51
 
52
52
  ## 아직 해결하지 않은 범위
53
53