@hatiolab/figure-model 0.3.3 → 0.3.4
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.
- package/dist/asset-types.d.ts +34 -3
- package/dist/asset-types.d.ts.map +1 -1
- package/dist/capabilities.js +28 -4
- package/dist/capabilities.js.map +1 -1
- package/dist/graph-types.d.ts +60 -1
- package/dist/graph-types.d.ts.map +1 -1
- package/dist/graph.d.ts.map +1 -1
- package/dist/graph.js +212 -21
- package/dist/graph.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/kernel-version.d.ts +1 -1
- package/dist/kernel-version.js +1 -1
- package/docs/assembly-constraints.md +3 -3
- package/docs/asset-persistence.md +8 -8
- package/docs/authoring-transactions.md +2 -2
- package/docs/capability-bindings.md +1 -1
- package/docs/common-kernel-experiment.md +2 -2
- package/docs/completeness-review-2026-10-04.md +150 -1
- package/docs/core-semantics.md +2 -2
- package/docs/cutover.md +4 -4
- package/docs/document-contract.md +3 -3
- package/docs/dryroom-profile-validation.md +1 -1
- package/docs/editor-integration.md +4 -4
- package/docs/evaluation-changes-design.md +304 -0
- package/docs/evaluation-performance-summary-2026-10-05.md +218 -0
- package/docs/full-conveyor-validation.md +8 -8
- package/docs/full-dryroom-validation.md +5 -5
- package/docs/full-forklift-validation.md +5 -5
- package/docs/full-robot-validation.md +4 -4
- package/docs/layout-system.md +2 -2
- package/docs/legacy-risk-audit-2026-09-23.md +14 -14
- package/docs/minimal-model.md +3 -3
- package/docs/openusd-review.md +14 -14
- package/docs/operator-contracts.md +4 -4
- package/docs/prototypes/README.md +2 -2
- package/docs/prototypes/asset.schema.json +1 -1
- package/docs/prototypes/document.schema.json +1 -1
- package/docs/prototypes/editor-browser.mjs +2 -2
- package/docs/prototypes/linear-comparison.py +1 -1
- package/docs/prototypes/render-dryroom.py +1 -1
- package/docs/prototypes/render-full-dryroom.mjs +12 -12
- package/docs/prototypes/runtime-browser.mjs +3 -3
- package/docs/research-review.md +1 -1
- package/docs/review-2026-09-22.md +19 -19
- package/docs/runtime-extraction.md +10 -10
- package/docs/sample-validation-expanded.md +5 -5
- package/docs/sample-validation.md +5 -5
- package/docs/shape-dimension-contract.md +1 -1
- package/docs/spatial-contracts.md +2 -2
- package/docs/status.md +1 -1
- package/docs/storage-integration.md +5 -5
- package/package.json +1 -1
|
@@ -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
|
이 패키지는 **이름 있는 부품의 치수·자세·반복·연결을 선언하고, 같은 정의를 저작·검사·씬에서 소비하는
|
package/docs/core-semantics.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Figure Model
|
|
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
|
-
제품은
|
|
274
|
+
제품은 단일 실행 체계를 쓴다. 기존 자산은 지금 형식으로 다시 작성해 교체한다.
|
|
275
275
|
복구용 원본 보관은 데이터 교체의 안전 절차이지 모델 설계 제약이 아니다.
|
|
276
276
|
현재 좌표를 고정한 변환과 반응형 의도를 복원한 재작성을 같은 성공으로 보고하지 않는다.
|
|
277
277
|
|
package/docs/cutover.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 단일 체계 전환 — 작업 기준
|
|
2
2
|
|
|
3
3
|
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
|
-
사용자 결정: 제품은
|
|
5
|
+
사용자 결정: 제품은 한 가지 형식만 쓴다. 그 형식의 단순성·일관성·저작성·품질을 우선하며, 버전별 편집 경로는 두지 않는다.
|
|
6
6
|
|
|
7
|
-
제품 모델러·AI·저장·렌더러는
|
|
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
|
-
이제 다음 제품 작업은
|
|
29
|
+
이제 다음 제품 작업은 Figure 생성·편집 명령을 실제 모델러의 사용자 동작에 연결하는 것이다. 호환 분기 추가는 하지 않는다. 패키지 설치·배포는 소스 구현과 구별해 확인한다.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Figure 그래프·capability 직렬화 계약 — 실험판
|
|
2
2
|
|
|
3
3
|
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
5
|
## 범위와 상태
|
|
6
6
|
|
|
7
|
-
실험 그래프와 capability 선언을 저장하고 재로드해 의미 검증하는 계약을 구현했다. **전체 Figure
|
|
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
|
|
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
|
-
상태: 독립
|
|
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
|
-
#
|
|
1
|
+
# Figure 편집 화면 연결 검증 — 실험판
|
|
2
2
|
|
|
3
3
|
> 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
4
|
|
|
5
5
|
## 완료 범위
|
|
6
6
|
|
|
7
|
-
저장된
|
|
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, 전체 `
|
|
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·렌더러를
|
|
50
|
+
제품 모델러·저장·AI·렌더러를 단일 경로로 전환한다. 기존 자산은 지금 형식으로 재작성한다. 호환 분기는 만들지 않는다. 제품에서는 src에서 빌드한 공용 API를 사용한다.
|
|
51
51
|
|
|
52
52
|
## 아직 해결하지 않은 범위
|
|
53
53
|
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# 일반 평가의 변경분 전달 설계 (검토용)
|
|
2
|
+
|
|
3
|
+
작성일: 2026-10-05 · 상태: 방향 승인(2026-10-05), 아래 보완 조건으로 구현 · 관련: ADR-0108(pose step), completeness review 2026-10-04 F1,
|
|
4
|
+
things-scene `src/figure/figure-rig.ts`
|
|
5
|
+
|
|
6
|
+
## 장면
|
|
7
|
+
|
|
8
|
+
모델러 사용자가 보드에서 컨베이어 60대를 함께 끌어 늘인다. 매 프레임 크기와 롤러 회전이 함께 바뀌므로 모든 인스턴스가
|
|
9
|
+
pose step이 아닌 일반 평가를 탄다. 브라우저 프레임 7~8 ms 가운데 커널 평가가 약 3 ms다. 문+램프 60대에서 flag가 문턱을
|
|
10
|
+
넘나들 때도 매 프레임 일반 평가다.
|
|
11
|
+
|
|
12
|
+
## 지금 일반 평가가 하는 일
|
|
13
|
+
|
|
14
|
+
rig는 프레임마다 `document.evaluator().advance(inputs)`를 부른다. pose step을 탈 수 없으면 `step`이 평가하고, 결과를
|
|
15
|
+
스냅샷으로 만든다. 스냅샷에는 값 레코드(롤러 컨베이어 421개 키), geometry 목록(40개 body), places가 들어간다. 바뀐 값과
|
|
16
|
+
body는 동결 사본으로, 형상은 제자리 동결로 공개된다(F1 계약).
|
|
17
|
+
|
|
18
|
+
크기 변경 프레임의 단계별 시간(Node, 롤러 컨베이어 60대, 프레임당 ms, `step` 안에 타이머를 넣어 잰 값이라 타이머
|
|
19
|
+
비용이 조금 들어 있다. 전체는 3.74~3.80 ms):
|
|
20
|
+
|
|
21
|
+
| 단계 | ms | 비율 |
|
|
22
|
+
| ------------------------------------------------------ | ----- | ---- |
|
|
23
|
+
| 연산 실행과 값 검사 | 1.65 | 44% |
|
|
24
|
+
| body 공개(사본·동결, 롤러 행 사본 24개 포함) | 0.95 | 25% |
|
|
25
|
+
| 바뀐 값 공개(값 레코드에 넣을 동결 사본) | 0.43 | 11% |
|
|
26
|
+
| 형상 제자리 동결 | 0.28 | 7% |
|
|
27
|
+
| step 밖(헛 pose step 시도, capabilities, advance) | 0.33 | 9% |
|
|
28
|
+
| 입력 검사·방문 목록 | 0.09 | 2% |
|
|
29
|
+
| geometry 목록 재구성, 값 레코드·목록 복사 | 0.05 | 1% |
|
|
30
|
+
|
|
31
|
+
함수별 self time으로 보면 공개(사본·동결) 32%, 검사 17%, step 관리 16%, 연산 25%였다(같은 장면, 프로파일러 50 µs 간격).
|
|
32
|
+
|
|
33
|
+
flag 장면(문+램프 60대)은 프레임당 0.20 ms, 인스턴스당 3.3 µs다. 공개 26%, 관리 20%, 검사 19%, 헛 pose step 시도 11%다.
|
|
34
|
+
|
|
35
|
+
## rig가 실제로 읽는 것
|
|
36
|
+
|
|
37
|
+
| 결과의 부분 | rig가 읽는가 |
|
|
38
|
+
| --------------------------- | ---------------------------------------------------------------------------- |
|
|
39
|
+
| geometry의 body | 읽는다. id, key, shape, pose. 모양이 같으면 같은 객체라는 점을 계획 재사용에 쓴다 |
|
|
40
|
+
| 값 레코드 | 외형(look)이 이름 붙인 visibility flag 몇 개만 읽는다. 421개 중 나머지는 읽지 않는다 |
|
|
41
|
+
| places(bindings) | 읽는다. 부착점 노드의 자세 |
|
|
42
|
+
| body·값의 동결 사본 | 읽기만 한다. 사본이 필요한 이유는 다른 호출자와 소유권 계약 때문이다 |
|
|
43
|
+
|
|
44
|
+
rig 밖의 소비자(`rig.evaluation()`, 선택, 상위 뷰, 저작 도구)는 스냅샷 전체를 읽는다. 이 경로는 그대로 둔다.
|
|
45
|
+
|
|
46
|
+
## 제안: 변경분 경로
|
|
47
|
+
|
|
48
|
+
변경분은 명시적으로 고른 evaluator만 받는다. `evaluator({ changes: true })`로 만든 evaluator의 `advance`는 일반 평가
|
|
49
|
+
대신 `kind: 'changes'`를 돌려준다. 옵션 없이 만든 evaluator는 지금처럼 `evaluation | poses`만 돌려준다. `evaluation | poses`를
|
|
50
|
+
처리하던 소비자가 새 종류를 받는 일은 없다. 다른 패키지(things-scene rig)가 쓰므로 타입과 수명 계약을 공개 타입으로
|
|
51
|
+
둔다. 결과는 pose step 결과(ADR-0108)를 넓힌 모양이다.
|
|
52
|
+
|
|
53
|
+
- `kind: 'changes'`, `generation`
|
|
54
|
+
- `bodies: Int32Array`, `poses: Float64Array(12×n)`: 이번 평가에서 다시 계산된 body의 슬롯과 자세 숫자. pose step과 같다.
|
|
55
|
+
- `shapes`: `bodies`의 각 슬롯의 형상. 형상은 이미 제자리에서 동결되어 공유되는 객체다. 다시 계산된 body는 형상이
|
|
56
|
+
같은 객체여도 함께 보낸다. 바뀌었는지는 소비자가 객체 동일성으로 판단한다.
|
|
57
|
+
- `structure`: generation이 바뀌었을 때만(첫 평가, 반복 개수 변경, 실패 뒤 재시작) 온다. 새 body 목록 전체의 `ids`와
|
|
58
|
+
`keys`다. 이때 `bodies`는 모든 슬롯을 담고, `shapes`와 `poses`도 모든 슬롯의 것이다. 소비자는 이것만으로 새 슬롯의
|
|
59
|
+
형상·자세·id·key를 모두 초기화할 수 있다. 커널은 이전 슬롯과 견주어 같은 형상을 빼고 보내지 않는다.
|
|
60
|
+
- `read(ref)`, `changed(ref)`: pose step과 같은 수명(다음 호출 뒤 `STEP_EXPIRED`). rig는 visibility flag를 이것으로 읽는다.
|
|
61
|
+
`read`는 숫자와 flag를 그대로 돌려주고, 객체는 매번 새로 만든 동결 사본으로 돌려준다. 수명 제한만으로는 내부 가변
|
|
62
|
+
객체의 노출을 막을 수 없기 때문이다.
|
|
63
|
+
- `places`: 읽는 값이 바뀐 부착점만 온다. `structure`가 올 때는 모든 부착점이 온다. place 안의 자세와 값도 `read`와 같은
|
|
64
|
+
동결 사본에서 만든다.
|
|
65
|
+
|
|
66
|
+
커널이 하는 일은 다음과 같다.
|
|
67
|
+
|
|
68
|
+
- 연산 실행과 검사는 지금과 같다. 같은 연산을 같은 순서로 실행하므로 숫자는 스냅샷과 비트 단위로 같다.
|
|
69
|
+
- 공개(사본·동결)를 미룬다. 마지막 스냅샷 이후 바뀐 슬롯과 body를 표시만 해 두고, 다음 `evaluate`나 스냅샷을 요구하는
|
|
70
|
+
`advance`가 올 때 그만큼만 공개한다. 바뀌지 않은 형상과 body가 스냅샷 사이에서 같은 객체로 이어지는 계약, 이전 결과가
|
|
71
|
+
바뀌지 않는 계약, 쓰기가 거절되는 계약은 그대로다.
|
|
72
|
+
- 형상의 제자리 동결은 지금처럼 만들 때 한다. 변경분 경로가 형상 객체를 넘기기 때문이다.
|
|
73
|
+
|
|
74
|
+
소유권은 다음과 같다. 변경분 경로가 넘기는 것은 typed array 사본(호출자 소유), 동결된 형상, 문자열, 수명이 정해진
|
|
75
|
+
`read`뿐이다. 커널 내부의 가변 객체는 넘기지 않으므로 F1 결함은 다시 열리지 않는다.
|
|
76
|
+
|
|
77
|
+
## 누적 변경과 스냅샷
|
|
78
|
+
|
|
79
|
+
- 변경분 호출을 여러 번 한 뒤의 `evaluate`는 같은 입력의 전체 평가와 같고, 마지막 스냅샷 이후 다시 계산된 값과 body만
|
|
80
|
+
새 객체다. 그 사이 여러 번 다시 계산된 body도 한 번만 공개된다.
|
|
81
|
+
- pose step과 변경분이 섞여도 같다. pose step은 evaluator의 슬롯을 바꾸지 않으므로, 그 뒤의 변경분과 스냅샷은 pose step이
|
|
82
|
+
움직인 입력을 바뀐 것으로 보고 다시 계산한다(지금 pose step 규칙과 같다).
|
|
83
|
+
- 값이 바뀌었다가 원래대로 돌아와도 다시 계산된 body는 새 객체다. 지금 스냅샷 경로와 같은 규칙이다.
|
|
84
|
+
- 실패 뒤 첫 호출은 처음 평가이고 `structure`를 담는다. 미뤄 둔 공개는 실패와 함께 버려진다.
|
|
85
|
+
|
|
86
|
+
## 포함해야 하는 경우
|
|
87
|
+
|
|
88
|
+
- 형상: 형상 객체가 바뀐 body만 `shapes`에 온다. rig는 그 슬롯의 geometry를 다시 얻고, 배치 계획을 형상 동일성으로 다시 판단한다.
|
|
89
|
+
- 반복 개수: 구조가 바뀌면 generation이 바뀌고 `ids`와 `keys`가 온다. rig는 지금 generation 변경에서 하듯 slots를 다시 만든다.
|
|
90
|
+
- 재질: 재질은 asset의 look에서 오며 평가 결과에 없다. 지금처럼 rig가 look으로 정한다. body의 look이 바뀌는 경우는
|
|
91
|
+
`keys`와 id로 정해지므로 구조 변경에 포함된다.
|
|
92
|
+
- visibility: flag의 값은 커널이 계산한 값을 `read`로 읽는다. rig는 문턱을 다시 계산하지 않는다.
|
|
93
|
+
- 부착점: 읽는 값이 바뀐 place만 capabilities가 계산해 넘긴다. 전체 bindings 재계산을 하지 않는다. 부착점의 목록은
|
|
94
|
+
asset의 선언(`capabilities.bindings`)으로 정해지며 평가 중에 생기거나 없어지지 않는다. place가 가리키는 대상(행의 사본
|
|
95
|
+
등)이 없어지면 그 평가는 실패한다. 실패한 동안 소비자는 마지막에 그린 place를 유지하고, 다음 성공한 호출은 `structure`와
|
|
96
|
+
함께 모든 place를 보낸다. 따라서 삭제와 재생성은 실패 뒤 재시작의 전체 place 목록으로 전달된다.
|
|
97
|
+
- 실패: 입력이 거절되거나 연산이 실패하면 지금과 같이 예외를 던지고 evaluator가 보관하던 것을 버린다. 미뤄 둔 공개도
|
|
98
|
+
함께 버린다. rig는 이미 그린 것을 유지하고, 다음 호출은 처음 평가로 시작한다.
|
|
99
|
+
|
|
100
|
+
렌더러가 Figure 의미를 재구현하지 않도록, 아래는 모두 커널과 capabilities가 정한다. body의 정체(id·key), 형상, 자세,
|
|
101
|
+
flag의 참·거짓, place의 자세, 구조 변경 여부다. rig는 받은 숫자와 객체를 그리기에 반영할 뿐이다.
|
|
102
|
+
|
|
103
|
+
## 예상 절감 범위
|
|
104
|
+
|
|
105
|
+
없어지는 것(Node, 크기 변경, 프레임당):
|
|
106
|
+
|
|
107
|
+
- body 공개 0.95 ms. 대신 다시 계산된 body의 자세 숫자를 typed array에 쓴다. 60대×40개 body×12개 숫자로, 0.1 ms를 넘지 않을 것으로
|
|
108
|
+
추정한다(따로 재지 않았다).
|
|
109
|
+
- 바뀐 값 공개 0.43 ms. rig가 읽는 flag만 `read`한다.
|
|
110
|
+
- 값 레코드·목록 복사와 전체 bindings 재계산 일부(합계 0.05 ms 안팎).
|
|
111
|
+
|
|
112
|
+
남는 것: 연산과 검사 1.65 ms, 형상 동결 0.28 ms, 입력 검사 0.09 ms, step 관리 일부.
|
|
113
|
+
|
|
114
|
+
추정: 커널 3.7 ms 중 1.2~1.4 ms(32~38%). 브라우저에서 커널이 3.0~3.3 ms이므로 같은 비율이면 프레임당 약 1.0~1.2 ms다
|
|
115
|
+
(프레임 7~8 ms의 13~16%). rig 쪽 `dress`(0.19~0.25 ms)도 다시 계산된 body만 다루게 되어 일부 줄 수 있다. 이 값은 Node
|
|
116
|
+
비율을 브라우저에 옮긴 추정이다. 확인은 브라우저 한 페이지 교차 A/B로 하며, 이번에 관찰한 A/A 변동 폭(블록 차이
|
|
117
|
+
중앙값 약 0.1~0.2 ms)보다 충분히 크다.
|
|
118
|
+
|
|
119
|
+
flag 장면은 인스턴스당 3.3 µs라 절감 여지가 프레임당 약 0.05 ms다. 이 장면은 이 경로로 줄일 대상이 아니다.
|
|
120
|
+
|
|
121
|
+
## 별도의 작은 후보: 헛 pose step 시도
|
|
122
|
+
|
|
123
|
+
`advance`는 pose step을 먼저 시도한다. 이때 바뀐 입력이 빠른 경로를 탈 수 있는지 보기 전에 `bindFast`(슬롯 배열 사본과
|
|
124
|
+
typed array 할당)를 한다. 직전 호출이 일반 평가였다면 `held.fast`가 비어 있어 매번 새로 만든다. 입력 검사도 pose step과
|
|
125
|
+
step에서 두 번 한다. 빠른 경로 판정을 먼저 하면 이 비용이 없어진다. 공개 계약에 영향이 없다. 크기 변경에서 프레임당
|
|
126
|
+
약 0.07 ms, flag에서 약 0.02 ms(그 장면 커널의 11%)로, 효과가 작아 측정은 블록 수를 늘린 A/B로 보조한다.
|
|
127
|
+
|
|
128
|
+
## 소비자 쪽 조건
|
|
129
|
+
|
|
130
|
+
- rig는 `evaluator({ changes: true })`를 명시적으로 고른다.
|
|
131
|
+
- `lastEvaluation`을 밖에서 직접 읽지 않더라도, `rig.evaluation()`과 그것을 쓰는 조회(`placeNode` 등)는 최신 값을 돌려준다.
|
|
132
|
+
`rig.evaluation()`은 evaluator의 `evaluate`(미룬 공개를 하는 스냅샷)로 만든다.
|
|
133
|
+
|
|
134
|
+
## 검증 계획
|
|
135
|
+
|
|
136
|
+
- 변경분을 적용한 결과가 같은 입력의 스냅샷(`evaluate`)과 같다: 모든 fixture, 무작위 입력 순서, 구조 변경 포함.
|
|
137
|
+
- 변경분 경로 뒤의 스냅샷이 F1 소유권 시험을 모두 통과한다. 미룬 공개가 이전 결과를 바꾸지 않는다.
|
|
138
|
+
- 실패 뒤의 다음 호출이 처음 평가와 같다.
|
|
139
|
+
- rig: 병합 없는 rig와 그리기가 같고, 선택(`bodyAt`), 부착점, sizing 시험이 그대로 통과한다.
|
|
140
|
+
- 성능: 크기 교대, 끌기(행 개수 변화), 회전, flag 장면의 frame 중앙값과 p95를 A/A와 함께 잰다.
|
|
141
|
+
|
|
142
|
+
## 결정 (2026-10-05)
|
|
143
|
+
|
|
144
|
+
1. 변경분은 `evaluator({ changes: true })`로 명시적으로 고른 소비자만 받는다. 기본 동작은 그대로다.
|
|
145
|
+
2. 미룬 공개는 `evaluate` 때 구성한다.
|
|
146
|
+
3. 예상 절감 1.0~1.2 ms는 목표값이다. 채택은 브라우저 전체 프레임 중앙값·p95와 메모리를 잰 뒤에 정한다. 발행하지 않는다.
|
|
147
|
+
|
|
148
|
+
## 구현과 측정 (2026-10-05)
|
|
149
|
+
|
|
150
|
+
구현(발행 안 함):
|
|
151
|
+
|
|
152
|
+
- figure-model `a968731`: pose step 시도가 빠른 경로 판정 전에 상태를 만들지 않는다(별도 커밋).
|
|
153
|
+
- `ac92b39`, `1d059f3`, 그 뒤 커밋: `evaluator({ changes: true })`로 고른 evaluator만 변경분을 받는다. `structure`에는
|
|
154
|
+
ids·keys·paths·indexes가 있다. 처음 평가의 공개도 스냅샷을 요구할 때까지 미룬다.
|
|
155
|
+
- 시험 `src/evaluation-changes.test.ts` 8개. 결함 9종(구조에서 슬롯 생략, `read`가 내부 객체 반환, 미룬 공개 소실, pose step이
|
|
156
|
+
쓴 body 누락, 기본 evaluator가 변경분을 받음, `evaluate`가 공개하지 않음, 첫 평가의 미룬 표시 누락 등)을 심어 실패를
|
|
157
|
+
확인했다. figure-model 시험 739개와 build가 통과한다.
|
|
158
|
+
- things-scene rig는 `changes: true`를 고르고, 알려 준 슬롯만 다시 입힌다. flag는 커널의 `read`로, place는 id로 갱신한다.
|
|
159
|
+
rig 시험(변경분 뒤 `lastEvaluation`과 `rig.evaluation()`이 스냅샷과 같음, 새로 만든 rig와 그리기가 같음, 변경분 옵션 선택)을
|
|
160
|
+
더했고, flag·place·옵션 결함을 심어 실패를 확인했다. figure 시험 79개가 형제 소스로 통과한다. 이 rig는 발행되지 않은
|
|
161
|
+
figure-model API가 있어야 빌드되므로 커밋하지 않고 로컬 브랜치 `candidate/figure-rig-changes`에 두었다.
|
|
162
|
+
|
|
163
|
+
측정(브라우저, 인스턴스 60개, frame 중앙값(p95) ms):
|
|
164
|
+
|
|
165
|
+
| 방식 | 크기 교대 | 끌기 | 회전·flag |
|
|
166
|
+
| -------------------------------------- | -------------------------------------- | -------------------------------------- | --------- |
|
|
167
|
+
| 한 페이지 A/A, 블록 차이 중앙값 | +0.02, +0.05 | +0.06, −0.01 | ±0.11 |
|
|
168
|
+
| 한 페이지 B/B(후보끼리), 블록 차이 | −0.03, +0.00 | +0.08, +0.11 | ±0.18 |
|
|
169
|
+
| 한 페이지 A/B, 블록 차이 | −1.14, −1.08 | −1.09, −0.91 | ±0.13 |
|
|
170
|
+
| 한 페이지 절대값, A/A 양쪽 → B/B 양쪽 | 6.88~7.38 → 6.69~6.81 | 7.01~7.93 → 7.00~7.40 | |
|
|
171
|
+
| 따로 띄운 실행, frame | 7.40 (9.88), 7.50 (14.86) → 5.77 (7.56), 6.33 (7.62) | 7.59 (9.45), 7.55 (9.72) → 6.74 (8.03), 5.73 (7.38) | |
|
|
172
|
+
| 따로 띄운 실행, rig `update` | 5.67, 5.56 → 4.10, 4.67 | 5.62, 5.67 → 4.58, 4.30 | |
|
|
173
|
+
|
|
174
|
+
- 한 페이지 A/B의 HEAD 쪽은 같은 회차의 A/A보다 느렸다(7.21·8.18 대 6.88~7.38). 두 쪽이 한 페이지에서 서로의 할당·GC에
|
|
175
|
+
영향을 주는 것으로 보인다. 그래서 짝지은 차이(약 −1 ms)는 개선을 부풀렸을 수 있다. 같은 조건의 절대값(A/A 대 B/B)으로는
|
|
176
|
+
크기 교대가 0.1~0.6 ms 줄었고, 끌기는 섞여 있다.
|
|
177
|
+
- 따로 띄운 실행에서는 frame 중앙값과 p95, rig `update`가 4회 모두 줄었다. 다만 이 방식의 A/A 변동은 이전에 최대 ±1.9 ms였다.
|
|
178
|
+
- 메모리(distinct 500대): heap 67.7 → 69.3 MB(+1.6 MB). 첫 평가 공개를 미루기 전에는 72.7 MB였다. 살아 있는 동안 39.3 →
|
|
179
|
+
41.1 MB, 60대 6.3 → 6.5 MB. 모두 dispose한 뒤 남는 양과 은행은 같다.
|
|
180
|
+
- 판정: rig `update`가 줄어든 것은 여러 방식에서 일관된다. 전체 프레임의 개선 크기는 측정 방식에 따라 0.1~1.8 ms로 갈리므로,
|
|
181
|
+
채택은 두 쪽이 서로 영향을 주지 않는 측정으로 확인한 뒤 정한다.
|
|
182
|
+
|
|
183
|
+
### 실행 단위 측정 (2026-10-05)
|
|
184
|
+
|
|
185
|
+
`things-scene/test/browser/check-figure-runs.mjs`로 쟀다. 같은 브라우저에서 한 번에 한 판의 페이지만 띄우고, 실행마다
|
|
186
|
+
rig·렌더러·context를 해제하고 페이지를 닫았다. 한 round에서 A1·A2(같은 판, A/A)·B를 한 번씩 돌리고, 6 round에서 순서
|
|
187
|
+
6가지를 한 번씩 썼다. 반복 수(6 round, 인스턴스 60, 워밍업 60, 실행당 300프레임)는 측정 전에 정했다. 값은 실행 중앙값의
|
|
188
|
+
중앙값(괄호 안은 p95의 중앙값) ms이고, 차이는 round별 짝 차이의 중앙값과 범위다.
|
|
189
|
+
|
|
190
|
+
| 구성 | A1 / A2 / B | A2−A1 중앙값 (범위) | B−A1 중앙값 (범위) | A2−A1 p95 | B−A1 p95 |
|
|
191
|
+
| ---------------------------- | ---------------------------------- | -------------------------- | --------------------------- | --------------- | ------------------------- |
|
|
192
|
+
| 크기 교대, 조회 없음 | 7.00 (8.74) / 6.96 (9.23) / 6.59 (8.89) | −0.03 (−0.23~−0.01) | −0.47 (−0.95~+0.08) | +0.22 (−0.36~+2.80) | +0.11 (−0.69~+1.80) |
|
|
193
|
+
| 크기 교대, 매 프레임 조회 | 7.05 (8.63) / 7.07 (8.46) / 7.12 (8.25) | +0.03 (−0.10~+0.12) | +0.09 (−0.10~+0.20) | −0.08 (−0.35~+0.23) | −0.34 (−0.53~−0.25) |
|
|
194
|
+
| 크기 교대, 30프레임마다 조회 | 7.82 (9.33) / 7.82 (9.90) / 7.47 (9.69) | −0.06 (−0.29~+0.26) | −0.30 (−0.42~−0.22) | +0.32 (−1.05~+0.71) | +0.42 (−3.18~+2.73) |
|
|
195
|
+
| 끌기(행 개수 변화), 조회 없음 | 7.22 (9.41) / 7.37 (9.53) / 6.67 (8.54) | +0.06 (−0.06~+0.20) | −0.63 (−0.98~+0.02) | +0.19 (−0.03~+0.64) | −0.38 (−1.38~+0.24) |
|
|
196
|
+
| 끌기, 매 프레임 조회 | 7.18 (8.36) / 7.14 (8.87) / 7.28 (8.47) | +0.00 (−0.09~+0.12) | +0.10 (−0.28~+0.22) | +0.05 (−4.03~+0.93) | +0.01 (−3.36~+0.50) |
|
|
197
|
+
| 회전(pose step만) | 6.07 (8.20) / 6.05 (8.13) / 5.86 (7.80) | +0.02 (−0.30~+0.59) | +0.06 (−1.24~+0.20) | −0.33 (−1.24~+1.05) | −0.35 (−1.56~+0.38) |
|
|
198
|
+
| 문+램프 flag | 3.25 (5.04) / 3.22 (4.80) / 3.19 (4.59) | +0.01 (−0.21~+0.11) | −0.12 (−0.37~−0.02) | −0.18 (−0.77~+0.07) | −0.41 (−1.25~+0.12) |
|
|
199
|
+
|
|
200
|
+
메모리(인스턴스 60, 페이지의 rig 생성 전 heap보다 늘어난 양, MB, 실행이 남긴 그대로 / 한 번 조회 뒤 / 30프레임 반복 조회 뒤):
|
|
201
|
+
|
|
202
|
+
| 구성 | A1 | B |
|
|
203
|
+
| ------------------ | -------------- | -------------- |
|
|
204
|
+
| 크기 교대, 조회 없음 | 8.1 / 8.1 / 8.1 | 8.4 / 8.9 / 9.1 |
|
|
205
|
+
| 끌기, 조회 없음 | 8.5 / 8.4 / 8.5 | 8.7 / 9.1 / 9.4 |
|
|
206
|
+
| 크기 교대, 매 프레임 조회 | 8.1 / 8.1 / 8.1 | 9.1 / 9.1 / 9.1 |
|
|
207
|
+
| 회전 | 8.2 / 8.1 / 8.2 | 8.4 / 8.4 / 8.5 |
|
|
208
|
+
| 문+램프 | 3.5 / 3.5 / 3.5 | 3.4 / 3.4 / 3.6 |
|
|
209
|
+
|
|
210
|
+
해석:
|
|
211
|
+
|
|
212
|
+
- 스냅샷을 읽지 않거나 가끔 읽는 소비자에서는 전체 프레임 중앙값이 줄었다. 크기 교대 −0.47 ms(6회 중 5회 감소), 30프레임마다
|
|
213
|
+
조회 −0.30 ms(6회 모두 감소), 끌기 −0.63 ms(6회 중 5회 감소)다. 짝 차이의 중앙값에서 개선을 관찰했지만, 개별 회차는
|
|
214
|
+
A/A 범위와 겹치거나 악화됐다(크기 교대 +0.08, 끌기 +0.02 ms인 회차가 있다).
|
|
215
|
+
- p95는 끌기에서만 대체로 줄었다(−0.38 ms, 6회 중 4회). 크기 교대의 p95 차이는 A/A의 p95 변동 범위 안이다.
|
|
216
|
+
- 매 프레임 `rig.evaluation()`을 읽으면 절감이 사라진다(크기 교대 +0.09, 끌기 +0.10 ms). 미룬 공개가 조회 때 돌아오기 때문이다.
|
|
217
|
+
- pose step만 도는 장면과 flag 장면은 A/A 범위 안이다.
|
|
218
|
+
- 메모리는 60대에서 0.2~1.0 MB 늘었다. 스냅샷을 한 번 읽은 뒤가 더 크다. 커널이 공개 사본을 갖고 있고, rig는 그와 별도로 자기
|
|
219
|
+
body를 갖기 때문이다. 이전에는 rig가 커널의 공개 사본을 그대로 썼다.
|
|
220
|
+
- 결론: 변경분 경로는 스냅샷을 매 프레임 읽지 않는 사용 조건에서 크기 변경 프레임의 중앙값을 0.3~0.6 ms 줄인다. p95의
|
|
221
|
+
일관된 개선은 끌기에서만 보였고, 매 프레임 조회에서는 이득이 없으며, 메모리가 조금 는다. 완료 기준(전체 프레임 중앙값과
|
|
222
|
+
p95의 일관된 개선)은 크기 교대 p95에서 충족되지 않았다. 후보는 브랜치에 두고 채택을 보류한다.
|
|
223
|
+
|
|
224
|
+
## 스냅샷 조회의 실제 사용 (2026-10-05 조사)
|
|
225
|
+
|
|
226
|
+
things-scene·things-factory·operato-application 세 저장소의 제품 소스(시험·번들 제외)에서 인스턴스 evaluator와 rig 스냅샷을
|
|
227
|
+
읽는 곳을 모두 찾았다.
|
|
228
|
+
|
|
229
|
+
| 읽는 곳 | 언제 | 읽는 항목 |
|
|
230
|
+
| ----------------------------------------- | -------------------------------------------------------------------- | ----------------------------- |
|
|
231
|
+
| `FigureRig.placeNode(id)` → `evaluation()` | 부착점 노드를 처음 만들 때, rig·부착점마다 한 번. 이후는 만든 노드를 쓴다. 호출은 운반물이 자리에 들어갈 때(`attachPointFor` → `placeAttachment`) | `bindings` 중 그 부착점 하나 |
|
|
232
|
+
| `figureTopView` → 새 rig의 `evaluate()` | 2D 평면도를 그릴 때, 크기 key가 바뀔 때만(`figure-instance.ts`의 `_top` 캐시) | geometry(형상·자세·표시), palette |
|
|
233
|
+
| rig 내부 `draw` | 매 갱신 | 변경분에서 만든 rig 자신의 body |
|
|
234
|
+
|
|
235
|
+
- 매 프레임 `rig.evaluation()`을 읽는 제품 소비자는 없다. `lastEvaluation`을 밖에서 읽는 곳은 시험뿐이다.
|
|
236
|
+
- figure-ui 모델러와 operato-application은 인스턴스 evaluator나 rig를 쓰지 않는다(전체 평가를 쓴다).
|
|
237
|
+
- 따라서 측정의 「매 프레임 조회」는 지금 제품에 없는 사용 조건이다. 실제로 문제가 되는 것은 드문 조회 한 번이 스냅샷 전체를
|
|
238
|
+
공개하고, 그 사본을 계속 보유하는 메모리다(60대에서 조회 전 +0.2~0.3 MB, 한 번 조회 뒤 +0.5~1.0 MB).
|
|
239
|
+
|
|
240
|
+
## 다음 순서 (설계, 구현 전)
|
|
241
|
+
|
|
242
|
+
1. 조회 범위를 줄인다.
|
|
243
|
+
- 커널(capabilities)이 변경분 evaluator에 부착점 하나를 묻는 조회를 둔다. 지금 상태에서 그 부착점이 읽는 값만 동결 사본으로
|
|
244
|
+
읽어 만든다(변경분의 `places`와 같은 규칙). 스냅샷을 만들지 않고, 다음 호출의 수명 제한도 필요 없다(반환 값이 호출자 소유다).
|
|
245
|
+
- `placeNode`는 이 조회를 쓴다. 부착점 의미는 커널에 남는다.
|
|
246
|
+
- 평면도는 한 번 쓰고 버리는 rig로 인스턴스 evaluator를 만들 이유가 없다. 전체 평가(가변, 동결 없음)를 rig와 같은 외형 규칙으로
|
|
247
|
+
입히는 경로를 둔다. 외형을 입히는 규칙은 rig의 것 하나를 함께 쓴다.
|
|
248
|
+
2. 커널의 공유 구조를 고친다.
|
|
249
|
+
- 스냅샷은 마지막 변경 뒤 첫 조회에서만 구성되고, 바뀌지 않은 재조회는 같은 body·값 객체를 다시 쓴다. 이것은 지금 구현이 이미
|
|
250
|
+
그렇다(미룬 공개가 없으면 공개하지 않는다). 값 레코드와 목록은 계약대로 호출마다 새로 만든다(60대 0.03 ms).
|
|
251
|
+
- 변경분이 다시 계산한 노드와 값의 공개 사본은 그 자리에서 놓는다. 다음 조회에서 어차피 새로 공개되므로 동일성 계약(바뀌지 않은
|
|
252
|
+
것만 같은 객체)은 그대로이고, 한 번 조회한 뒤 쌓이던 낡은 사본이 남지 않는다.
|
|
253
|
+
- 변경분 소비자와 스냅샷이 같은 동결 body를 나눠 쓰려면 변경될 때마다 body를 공개(사본·동결)해야 한다. 이것은 변경분 경로가 없애려던
|
|
254
|
+
비용이다. 그래서 body는 나누지 않고, 지금처럼 동결된 형상만 나눈다.
|
|
255
|
+
3. 가변 렌더 버퍼와 공개 불변 결과를 나눈다.
|
|
256
|
+
- 변경분의 typed array는 호출자 소유의 가변 버퍼다. 형상은 커널의 동결 객체를 그대로 공유한다. 스냅샷은 동결된 공개 결과다.
|
|
257
|
+
- rig의 `lastEvaluation`은 rig가 변경분으로 만든 자기 그리기 상태다. 커널 스냅샷의 객체를 담지 않는다. 밖에서 최신 값을 원하면
|
|
258
|
+
`rig.evaluation()`(커널 스냅샷)을 읽는다.
|
|
259
|
+
|
|
260
|
+
예상: 지금 제품의 사용 조건(조회 드묾)에서 프레임 시간은 바뀌지 않는다. 1번으로 부착점 조회가 스냅샷 전체 공개를 일으키지 않게 되고,
|
|
261
|
+
2번으로 조회 뒤의 메모리 증가가 줄어든다. 매 프레임 전체 스냅샷을 요구하는 소비자가 생기면 공개 비용은 피할 수 없다. 크기 교대 p95의
|
|
262
|
+
완료 기준 미충족은 이 순서로 바뀌지 않는다.
|
|
263
|
+
|
|
264
|
+
## 조회 범위 축소와 낡은 사본 해제 (2026-10-05)
|
|
265
|
+
|
|
266
|
+
구현:
|
|
267
|
+
|
|
268
|
+
- figure-model: 인스턴스 evaluator의 `value(ref)`와 capabilities의 `place(id)`. 지금 상태(마지막 평가와 그 뒤의 pose step)를
|
|
269
|
+
동결 사본으로 읽어 만들고 스냅샷을 만들지 않는다. 반환값은 호출자 소유다. pose step이 자세만 쓴 행(아무 노드도 읽지 않는 행)은
|
|
270
|
+
물을 때 그 자리에서 실행한다. 두 종류의 evaluator 모두에 있다.
|
|
271
|
+
- figure-model: 변경분 단계는 다시 계산한 노드와 값의 공개 사본을 놓는다. 호출자가 가진 스냅샷은 건드리지 않고, 다시 계산되지
|
|
272
|
+
않은 것은 다음 스냅샷에서 같은 객체다.
|
|
273
|
+
- things-scene 후보 브랜치(`candidate/figure-rig-changes` `8b7c0ce2`): `placeNode`가 `place(id)`를 쓴다. 평면도는
|
|
274
|
+
`evaluateOnce()`(전체 평가를 rig의 외형 규칙 하나로 입힘, 인스턴스 evaluator 없음)를 쓴다. 외형 규칙은 `dressOne` 하나로
|
|
275
|
+
스냅샷·변경분·전체 평가가 함께 쓴다. `lastEvaluation`은 `lastDrawn`(`FigureRigDrawing`, rig 자신의 그리기 상태)으로 이름과
|
|
276
|
+
타입을 바꿨다. 커널 스냅샷은 `evaluation()`이다.
|
|
277
|
+
|
|
278
|
+
시험: figure-model `src/evaluation-reads.test.ts` 3개(부착점 단건 조회가 두 종류 evaluator에서 pose step 뒤에도 전체 평가와 같음,
|
|
279
|
+
값 조회의 소유권, 보관한 스냅샷은 그대로이고 놓은 스냅샷의 다시 계산된 body는 회수되며 바뀌지 않은 body는 같은 객체). 결함
|
|
280
|
+
5종(해제 안 함, 바뀌지 않은 것까지 해제, pose step 무시, 내부 객체 반환, 행 실행 누락)을 심어 실패를 확인했다. things-scene
|
|
281
|
+
후보에 시험 2개(부착점 단건 조회는 스냅샷을 만들지 않고, 재사용된 노드가 pose step·평가 뒤에도 커널의 자리이며 그린 상태의
|
|
282
|
+
region까지 같음 · 평면도의 전체 평가가 스냅샷 경로와 geometry·palette·places·크기 결과가 같음). 결함 3종을 심어 실패를 확인했다.
|
|
283
|
+
|
|
284
|
+
메모리(Node, 컨베이어 60대에 부착점 하나, GC 뒤 rig 생성 전보다 늘어난 MB, 예열 한 번 뒤 두 번씩, 두 번의 차이 0.1 MB 이내).
|
|
285
|
+
각 단계의 결과는 전체 평가와 같았다.
|
|
286
|
+
|
|
287
|
+
| 단계 | HEAD rig, 놓음 | HEAD rig, 보관 | 후보·해제 없음, 놓음 | 후보·해제 없음, 보관 | 후보·해제, 놓음 | 후보·해제, 보관 |
|
|
288
|
+
| ---------------------- | -------------- | -------------- | -------------------- | -------------------- | --------------- | --------------- |
|
|
289
|
+
| 조회 전 | 6.35~6.39 | 6.38~6.43 | 6.53~6.56 | 6.54~6.58 | 6.53~6.57 | 6.53~6.58 |
|
|
290
|
+
| 부착점 단건 조회 뒤 | 6.35~6.39 | 6.34~6.39 | 6.42~6.49 | 6.43~6.51 | 6.42~6.49 | 6.43~6.51 |
|
|
291
|
+
| 전체 스냅샷 조회 뒤 | 6.35~6.38 | 6.40~6.47 | 7.39~7.44 | 7.47~7.52 | 7.39~7.45 | 7.47~7.52 |
|
|
292
|
+
| 30프레임 변경 뒤 | 6.34~6.42 | 7.88~7.95 | 8.05~8.15 | 8.17~8.24 | 7.77~7.87 | 7.90~7.97 |
|
|
293
|
+
| 재조회 뒤 | 6.41~6.45 | 7.91~7.96 | 7.56~7.62 | 8.94~9.02 | 7.56~7.61 | 8.94~8.99 |
|
|
294
|
+
| dispose 뒤 | 0.01~0.08 | 0.03~0.09 | 0.01~0.08 | 0.02~0.10 | 0.01~0.08 | 0.02~0.10 |
|
|
295
|
+
|
|
296
|
+
- 부착점 단건 조회는 메모리를 늘리지 않는다. 지금까지는 이 조회가 스냅샷 전체를 공개했다.
|
|
297
|
+
- 낡은 사본 해제로 스냅샷 조회 뒤 변경 단계의 보유량이 0.3 MB 줄었다(8.05~8.24 → 7.77~7.97).
|
|
298
|
+
- 그래도 스냅샷을 한 번 읽은 뒤에는 후보가 HEAD rig보다 놓은 경우 1.1~1.2 MB, 보관한 경우 1.0 MB 더 쓴다. HEAD에서는 rig가 커널의
|
|
299
|
+
공개 사본을 그대로 쓰므로 공개 사본이 하나뿐이다. 후보에서는 커널의 공개 사본(바뀌지 않은 것의 동일성 계약 때문에 유지)과 rig
|
|
300
|
+
자신의 body가 따로 있고, `evaluation()`이 입힌 사본도 rig의 입힘 캐시에 남는다.
|
|
301
|
+
- 지금 제품에서 스냅샷을 읽는 곳은 부착점(이제 단건 조회)과 평면도(이제 전체 평가)뿐이다. 그래서 제품 사용 조건에서는 스냅샷 공개가
|
|
302
|
+
일어나지 않고, 보유량은 「조회 전」 줄(HEAD보다 0.15~0.2 MB)에 머문다.
|
|
303
|
+
- 이 작업은 조회 비용과 메모리의 개선이다. 크기 교대 p95가 완료 기준을 채우지 못한 문제는 그대로이고, 변경분 경로의 기본 채택은
|
|
304
|
+
보류한다.
|