@hatiolab/figure-model 0.6.7 → 0.7.1

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 (127) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +8 -4
  3. package/dist/asset-types.d.ts +8 -13
  4. package/dist/asset-types.d.ts.map +1 -1
  5. package/dist/asset-types.js.map +1 -1
  6. package/dist/asset.js +4 -4
  7. package/dist/asset.js.map +1 -1
  8. package/dist/authoring-actions.js +18 -5
  9. package/dist/authoring-actions.js.map +1 -1
  10. package/dist/authoring-types.d.ts +6 -11
  11. package/dist/authoring-types.d.ts.map +1 -1
  12. package/dist/authoring-types.js.map +1 -1
  13. package/dist/editor-workspace.d.ts +1 -1
  14. package/dist/editor-workspace.d.ts.map +1 -1
  15. package/dist/editor-workspace.js +13 -6
  16. package/dist/editor-workspace.js.map +1 -1
  17. package/dist/extensions.d.ts +15 -0
  18. package/dist/extensions.d.ts.map +1 -0
  19. package/dist/extensions.js +63 -0
  20. package/dist/extensions.js.map +1 -0
  21. package/dist/gate.d.ts +1 -1
  22. package/dist/gate.d.ts.map +1 -1
  23. package/dist/gate.js +28 -33
  24. package/dist/gate.js.map +1 -1
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/input-preview.d.ts +48 -0
  30. package/dist/input-preview.d.ts.map +1 -0
  31. package/dist/{authoring-session.js → input-preview.js} +7 -63
  32. package/dist/input-preview.js.map +1 -0
  33. package/dist/kernel-version.d.ts +1 -1
  34. package/dist/kernel-version.js +1 -1
  35. package/dist/names.d.ts.map +1 -1
  36. package/dist/names.js +5 -1
  37. package/dist/names.js.map +1 -1
  38. package/dist/package.d.ts.map +1 -1
  39. package/dist/package.js +18 -15
  40. package/dist/package.js.map +1 -1
  41. package/dist/proposal.d.ts +5 -1
  42. package/dist/proposal.d.ts.map +1 -1
  43. package/dist/proposal.js +18 -5
  44. package/dist/proposal.js.map +1 -1
  45. package/dist/release-contract.d.ts +1 -1
  46. package/dist/release-contract.d.ts.map +1 -1
  47. package/dist/release-contract.js +13 -24
  48. package/dist/release-contract.js.map +1 -1
  49. package/dist/shape-edit.d.ts +1 -1
  50. package/dist/shape-edit.d.ts.map +1 -1
  51. package/dist/size-edit.d.ts +1 -1
  52. package/dist/size-edit.d.ts.map +1 -1
  53. package/docs/asset-persistence.md +6 -3
  54. package/docs/authoring-transactions.md +21 -19
  55. package/docs/capability-bindings.md +6 -3
  56. package/docs/common-kernel-experiment.md +3 -0
  57. package/docs/document-contract.md +6 -3
  58. package/docs/dryroom-profile-validation.md +3 -0
  59. package/docs/editor-integration.md +5 -2
  60. package/docs/full-conveyor-validation.md +5 -2
  61. package/docs/full-dryroom-validation.md +6 -3
  62. package/docs/full-forklift-validation.md +5 -2
  63. package/docs/full-robot-validation.md +5 -2
  64. package/docs/payload-collision-validation.md +5 -2
  65. package/docs/payload-contact-validation.md +5 -2
  66. package/docs/prototypes/README.md +27 -61
  67. package/docs/repeated-binding-validation.md +6 -3
  68. package/docs/review-2026-09-22.md +3 -0
  69. package/docs/runtime-extraction.md +9 -2
  70. package/docs/sample-validation-expanded.md +3 -0
  71. package/docs/sample-validation.md +3 -0
  72. package/docs/shape-contract.md +7 -5
  73. package/docs/spatial-contracts.md +3 -0
  74. package/docs/status.md +2 -1
  75. package/docs/storage-integration.md +6 -3
  76. package/docs/typed-repeat-contracts.md +3 -0
  77. package/package.json +9 -9
  78. package/dist/authoring-session.d.ts +0 -121
  79. package/dist/authoring-session.d.ts.map +0 -1
  80. package/dist/authoring-session.js.map +0 -1
  81. package/dist/carrier.d.ts +0 -23
  82. package/dist/carrier.d.ts.map +0 -1
  83. package/dist/carrier.js +0 -65
  84. package/dist/carrier.js.map +0 -1
  85. package/docs/prototypes/asset-samples.mjs +0 -15
  86. package/docs/prototypes/asset-store.mjs +0 -52
  87. package/docs/prototypes/asset-store.test.mjs +0 -59
  88. package/docs/prototypes/asset.mjs +0 -1
  89. package/docs/prototypes/asset.schema.json +0 -36
  90. package/docs/prototypes/asset.test.mjs +0 -68
  91. package/docs/prototypes/authoring-session.mjs +0 -1
  92. package/docs/prototypes/authoring-session.test.mjs +0 -65
  93. package/docs/prototypes/capability-plan.mjs +0 -1
  94. package/docs/prototypes/capability-plan.test.mjs +0 -56
  95. package/docs/prototypes/capability-samples.mjs +0 -23
  96. package/docs/prototypes/document.mjs +0 -2
  97. package/docs/prototypes/document.schema.json +0 -66
  98. package/docs/prototypes/document.test.mjs +0 -55
  99. package/docs/prototypes/dryroom-mesh.mjs +0 -60
  100. package/docs/prototypes/dryroom-mesh.test.mjs +0 -30
  101. package/docs/prototypes/editor-browser.mjs +0 -97
  102. package/docs/prototypes/editor-workspace.mjs +0 -1
  103. package/docs/prototypes/editor-workspace.test.mjs +0 -35
  104. package/docs/prototypes/feature-pattern.test.mjs +0 -131
  105. package/docs/prototypes/full-conveyor.mjs +0 -60
  106. package/docs/prototypes/full-conveyor.test.mjs +0 -61
  107. package/docs/prototypes/full-dryroom.mjs +0 -67
  108. package/docs/prototypes/full-dryroom.test.mjs +0 -54
  109. package/docs/prototypes/full-forklift.mjs +0 -40
  110. package/docs/prototypes/full-forklift.test.mjs +0 -37
  111. package/docs/prototypes/full-robot.mjs +0 -35
  112. package/docs/prototypes/full-robot.test.mjs +0 -68
  113. package/docs/prototypes/kernel.mjs +0 -147
  114. package/docs/prototypes/kernel.test.mjs +0 -144
  115. package/docs/prototypes/more-samples.test.mjs +0 -182
  116. package/docs/prototypes/payload-collision.mjs +0 -54
  117. package/docs/prototypes/payload-collision.test.mjs +0 -68
  118. package/docs/prototypes/payload-fit.mjs +0 -58
  119. package/docs/prototypes/payload-fit.test.mjs +0 -59
  120. package/docs/prototypes/render-dryroom.py +0 -60
  121. package/docs/prototypes/render-full-dryroom.mjs +0 -86
  122. package/docs/prototypes/repeated-binding.mjs +0 -13
  123. package/docs/prototypes/repeated-binding.test.mjs +0 -46
  124. package/docs/prototypes/runtime-browser.mjs +0 -76
  125. package/docs/prototypes/samples.test.mjs +0 -144
  126. package/docs/prototypes/spatial-plan.test.mjs +0 -102
  127. package/docs/prototypes/typed-repeat.test.mjs +0 -96
@@ -1,14 +1,17 @@
1
1
  # 반복 요소의 기능/표면 참조 — 실험 검증
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
7
 
5
8
  ## 이번 구현
6
9
 
7
10
  전체 컨베이어의 반복 롤러를 선택하고 그 실제 끝면을 binding pose와 contact 후보로 사용할 수 있도록 했다. 반복 template를 별도 메시로 만들거나 선택한 항목을 한 번 더 렌더링하지 않는다.
8
11
 
9
- - [예제](prototypes/repeated-binding.mjs)
10
- - [테스트](prototypes/repeated-binding.test.mjs)
11
- - [capability compiler](prototypes/capability-plan.mjs)
12
+ - [예제](https://github.com/heartyoh/figure-model/blob/3d79ec4/docs/prototypes/repeated-binding.mjs)
13
+ - [테스트](https://github.com/heartyoh/figure-model/blob/3d79ec4/docs/prototypes/repeated-binding.test.mjs)
14
+ - [capability compiler](https://github.com/heartyoh/figure-model/blob/3d79ec4/docs/prototypes/capability-plan.mjs)
12
15
 
13
16
  현재 선언 버전은 `r3-capability-3`이다. pose는 기존 transform 출력 ID 또는 `{placement, feature}` 중 하나다. 후자는 실제 표면 출처 검사와 같은 경로로 처리한다. V1/V2 입력은 묵시적으로 바꾸지 않고 거부한다. 제품 데이터 마이그레이션을 수행한 것은 아니다.
14
17
 
@@ -1,5 +1,8 @@
1
1
  # Figure 평가 — figure 레인, 2026-09-22
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  figure-model 0.1.32 (`54d30c2`) 기준. 문서를 읽고 판단한 것이 아니라 **돌려서 확인한 것**을 적는다.
4
7
  확인에 쓴 명령은 항목마다 적어 두었다.
5
8
 
@@ -1,5 +1,8 @@
1
1
  # Figure 런타임 정식 소스 이관 — 그래프·capability·자산
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
7
 
5
8
  > 최신 작업 기준: [단일 체계 전환](cutover.md). 아래의 버전별 제품 연결 방향은 과거 작업 기록이며, 향후 설계 조건에서 제외한다.
@@ -78,7 +81,11 @@
78
81
 
79
82
  ## 편집 트랜잭션·workspace 이관
80
83
 
81
- `src/authoring-session.ts`와 `src/editor-workspace.ts`를 추가했다. 패키지 루트에서 `createFigureAuthoringSession`, `createFigureEditorWorkspace`와 요청·반환 타입을 제공한다. 기존 실험 파일 두 개는 re-export만 남겼다. 이번 두 모듈은 `any` 없이 기존 strict 설정으로 검사한다. 하위 평가기의 내부 Dynamic 경계까지 제거한 것은 아니다.
84
+ 이관 당시 `src/authoring-session.ts`와 `src/editor-workspace.ts`를 추가하고, 두 생성 함수와 요청·반환 타입을 패키지 루트에서 제공했다.
85
+ 두 모듈은 `any` 없이 strict 설정으로 검사했다. 하위 평가기의 내부 Dynamic 경계까지 제거한 것은 아니다.
86
+
87
+ 2026-10-16에 사용하지 않는 입력 세션 API와 해당 프로토타입·시험을 삭제했다. 현재 수정 번호·적용·읽기·undo/redo는
88
+ 편집 작업 공간이 관리하고, 입력 미리보기는 내부 함수로만 남는다. 아래는 이관 당시의 계약과 검증 기록이다.
82
89
 
83
90
  유지한 편집 계약:
84
91
 
@@ -93,7 +100,7 @@ workspace 이관 당시 검증: 소스 테스트 **451개**, 실험 테스트 **
93
100
 
94
101
  별도로 격리 편집 UI에서 포크1275mm 수정 → HTTP 파일 저장 → 로봇 전환 → 저장본 복원 → 빈 화면의 경로를 다시 통과했다. page error0개. 생성된 편집 화면과 빈 캔버스 스크린샷을 직접 확인했다. 이 UI는 제품 서버가 아니며 테스트 후 임시 저장 파일을 정리한다.
95
102
 
96
- ### 편집 계층의 남은 제한
103
+ ### 이관 당시 편집 계층의 제한
97
104
 
98
105
  - 선언된 입력값 편집과 상자 추가 트랜잭션을 지원한다. 구조 변경과 입력 변경은 workspace의 동일 undo/redo 이력에 포함된다. 다른 primitive 추가·삭제·재질·관계 편집은 남아 있다.
99
106
  - context는 한 workspace 안의 열기 세대다. 전역 자산 ID·사용자 권한·영속 대화 세션 ID를 대체하지 않는다.
@@ -1,5 +1,8 @@
1
1
  # Figure 샘플 검증 확대 — 16종
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
7
 
5
8
  2026-09-20. [1차 검사](sample-validation.md)의 후속이다.
@@ -1,5 +1,8 @@
1
1
  # Figure 실제 샘플 대입 검증 — 2026-09-20
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
7
 
5
8
  후속: [제품 시드 전체 + fixture 2종, 총 16종 확대 검증](sample-validation-expanded.md).
@@ -59,9 +59,11 @@ What the kernel does now, where it differs from the text below, and why. Branch
59
59
  be fastened to, it is not a surface a binding holds things on, and its preview is a line.
60
60
  - **Commands built:** `set-section-corner` and `set-cavity` (§7). An edit that takes away a face something refers to
61
61
  is refused with `FEATURE_MAPPING_REQUIRED`. Mapping to another face is not built yet.
62
- - **The one-time rewrite:** `scripts/rewrite-shapes.ts` and `scripts/rewrite-shapes-files.ts`. A file is written only
63
- when every body's world box and pose agree with the old kernel's (0.1.95) at the drawn values, at half and twice
64
- the size, and at each state input's ends. All 24 fixtures agree.
62
+ - **The one-time rewrite:** `scripts/rewrite-shapes.ts` and `scripts/rewrite-shapes-files.ts` wrote a file only when
63
+ every body's world box and pose agreed with the old kernel's (0.1.95) at the drawn values, at half and twice the
64
+ size, and at each state input's ends. All 24 fixtures agreed. The scripts were removed after migration. A read-only check on 2026-10-16 found no old
65
+ shape operators in 65 production drafts, 6 release records, the templates or the fixtures.
66
+ The scripts are available in history at `a3ed90a`.
65
67
  - **Q10 (ruled 2026-09-29, "make it large enough"):** the node limit is 8192 (`FIGURE_DOCUMENT_NODE_LIMIT`), a fence against malformed documents; the 1 MiB limit binds first. No start shorthand.
66
68
  A start node per part took two stored figures, of 493 and 497 nodes, past 512. The alternative is a `start` left out
67
69
  for a centred push, which is a stored shorthand and a change of format.
@@ -344,8 +346,8 @@ triangulation and a full re-evaluation of the figure at 64, 256 and 1024 points
344
346
 
345
347
  ## 7. Commands
346
348
 
347
- All of them go through the authoring session, which checks the model and revision, applies atomically, and undoes
348
- in one step. The modeller, the AI and the templates use them and nothing else (ADR-0100 decision 6).
349
+ The modeller sends these commands through the editor workspace, which checks the context and revision, applies
350
+ atomically, and undoes in one step. AI proposals and templates use the same authoring commands (ADR-0100 decision 6).
349
351
 
350
352
  | command | what it changes |
351
353
  | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
@@ -1,5 +1,8 @@
1
1
  # Figure 타입·공간 그래프 통합 실험
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
7
 
5
8
  후속: [드라이룸 실제 단면·메시 검증](dryroom-profile-validation.md).
package/docs/status.md CHANGED
@@ -20,4 +20,5 @@
20
20
  - 제품 서버 localhost:3300 은 이 형식으로 돈다(figure-model 0.1.92 · things-scene 10.1.60 · tf 10.1.75).
21
21
  - 시험: `npm test`(타입 검사 + `src/*.test.ts`). 부품 지우기·복제의 부작용 시험은
22
22
  `src/edit-side-effects.test.ts` — 도형 16 개의 모든 부품을 지우고 복제해 나머지가 그대로인지 본다.
23
- - 실험 기록: `docs/prototypes/*.test.mjs` 와 날짜가 붙은 `docs/*.md` 는 당시의 기록이다.
23
+ - 날짜가 붙은 검증 문서는 당시 기록이다. 2026-10-16에 폐기된 시제품을 정리했고, 현재 유지하는 30개 시험은
24
+ `npm run test:prototypes`로 실행하며 `npm test`에도 포함한다. [시제품 안내](prototypes/README.md)를 따른다.
@@ -1,14 +1,17 @@
1
1
  # Figure 저장 API 경계와 파일 영속화 검증
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
7
 
5
8
  ## 이번 단계의 결과
6
9
 
7
10
  격리 편집 화면의 메모리 저장을 **HTTP 요청 → 의미 검증 → 파일 저장 → 저장 확인**으로 변경했다. 저장한 자산은 파일에서 다시 열며, 별도 Node 프로세스에서도 복원한다. 실제 제품의 GraphQL API·DB·기존 자산은 변경하지 않았다.
8
11
 
9
- - [파일 저장소](prototypes/asset-store.mjs)
10
- - [저장·충돌·별도 프로세스 복원 테스트](prototypes/asset-store.test.mjs)
11
- - [브라우저 연결](prototypes/editor-browser.mjs)
12
+ - [파일 저장소](https://github.com/heartyoh/figure-model/blob/3d79ec4/docs/prototypes/asset-store.mjs)
13
+ - [저장·충돌·별도 프로세스 복원 테스트](https://github.com/heartyoh/figure-model/blob/3d79ec4/docs/prototypes/asset-store.test.mjs)
14
+ - [브라우저 연결](https://github.com/heartyoh/figure-model/blob/3d79ec4/docs/prototypes/editor-browser.mjs)
12
15
 
13
16
  ## 왜 기존 저장 API에 바로 연결하지 않았는가
14
17
 
@@ -1,5 +1,8 @@
1
1
  # 반복 조립체의 typed graph 통합
2
2
 
3
+ > 2026-10-16 정리: 본문의 옛 시제품 실행 명령과 통과 수는 당시 기록이다. 폐기된 형식·외부 시료에 의존하는 코드는 삭제했고,
4
+ > 해당 소스 링크는 삭제 전 커밋을 가리킨다. 현재 실행 가능한 시험과 대체 검증 경로는 [시제품 안내](prototypes/README.md)를 따른다.
5
+
3
6
  > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
7
 
5
8
  상태: 독립 실험. 제품 런타임·원본 시드·DB 변경 없음.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatiolab/figure-model",
3
- "version": "0.6.7",
3
+ "version": "0.7.1",
4
4
  "description": "The figure format (figure-asset-1): a kernel that evaluates a figure from its declared relations, the authoring commands a modeller and an AI share, the release gate and the score.",
5
5
  "keywords": [
6
6
  "figure",
@@ -15,12 +15,12 @@
15
15
  "author": "heartyoh@hatiolab.com",
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "git+https://github.com/hatiolab/figure-model.git"
18
+ "url": "git+https://github.com/heartyoh/figure-model.git"
19
19
  },
20
20
  "bugs": {
21
- "url": "https://github.com/hatiolab/figure-model/issues"
21
+ "url": "https://github.com/heartyoh/figure-model/issues"
22
22
  },
23
- "homepage": "https://github.com/hatiolab/figure-model#readme",
23
+ "homepage": "https://github.com/heartyoh/figure-model#readme",
24
24
  "type": "module",
25
25
  "sideEffects": false,
26
26
  "main": "dist/index.js",
@@ -48,15 +48,15 @@
48
48
  "version": "node scripts/sync-kernel-version.mjs && git add src/kernel-version.ts",
49
49
  "build": "tsc -p tsconfig.build.json",
50
50
  "check": "tsc -p tsconfig.json --noEmit",
51
- "test": "npm run check && FIGURE_FREEZE_COMPILED=1 node --test src/*.test.ts",
52
- "test:coverage:slot-layout": "node --test --experimental-test-coverage --test-coverage-include=src/slot-layout.ts --test-coverage-include=src/slot-places.ts --test-coverage-lines=100 --test-coverage-branches=95 --test-coverage-functions=95 src/slot-layout.test.ts src/slot-places.test.ts",
53
- "test:rewrite": "node --test scripts/*.test.ts",
51
+ "test": "npm run check && FIGURE_FREEZE_COMPILED=1 node --test src/*.test.ts && npm run test:prototypes",
52
+ "test:coverage:slot-layout": "FIGURE_FREEZE_COMPILED=1 node --test --experimental-test-coverage --test-coverage-include=src/slot-layout.ts --test-coverage-include=src/slot-places.ts --test-coverage-lines=100 --test-coverage-branches=95 --test-coverage-functions=95 src/slot-layout.test.ts src/slot-places.test.ts",
54
53
  "test:released": "node --test scripts/released-kernel.check.ts",
55
- "test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=100 --test-coverage-branches=95 --test-coverage-functions=100 src/*.test.ts",
54
+ "test:coverage": "FIGURE_FREEZE_COMPILED=1 node --test --experimental-test-coverage --test-coverage-lines=97 --test-coverage-branches=90 --test-coverage-functions=96 src/*.test.ts",
56
55
  "format": "prettier --write \"src/**/*.ts\" \"docs/**/*.md\" \"*.md\" \"*.json\"",
57
56
  "format:check": "prettier --check \"src/**/*.ts\" \"docs/**/*.md\" \"*.md\" \"*.json\"",
58
57
  "clean": "rm -rf dist",
59
- "prepublishOnly": "npm run clean && npm run check && npm test && npm run build"
58
+ "prepublishOnly": "npm run clean && npm run check && npm test && npm run build",
59
+ "test:prototypes": "node --test docs/prototypes/*.test.mjs"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/node": "^26.4.1",
@@ -1,121 +0,0 @@
1
- import type { FigureDocument, FigureCapabilityEvaluation } from './asset-types.ts';
2
- import type { FigureUnit } from './graph-types.ts';
3
- export interface FigureEditControl {
4
- origin: 'ui' | 'ai';
5
- expectedRevision: number;
6
- /** The clips the author agreed to let go, as a CLIPS_DROPPED refusal named them (clip-keeping.ts). */
7
- dropClips?: readonly string[];
8
- }
9
- export interface FigureInputChange {
10
- kind: 'set-design' | 'set-state';
11
- input: string;
12
- unit: FigureUnit;
13
- value: number;
14
- }
15
- export interface FigureEditRequest extends FigureEditControl {
16
- changes: FigureInputChange[];
17
- }
18
- export declare function createFigureAuthoringSession(document: FigureDocument, initialInputs: Record<string, number>): {
19
- read: () => {
20
- revision: number;
21
- inputs: Record<string, number>;
22
- evaluation: FigureCapabilityEvaluation;
23
- canUndo: boolean;
24
- canRedo: boolean;
25
- };
26
- preview(q: FigureEditRequest): {
27
- candidate: {
28
- inputs: Record<string, number>;
29
- evaluation: FigureCapabilityEvaluation;
30
- };
31
- baseRevision: number;
32
- origin: "ui" | "ai";
33
- changes: {
34
- before: number | undefined;
35
- kind: "set-design" | "set-state";
36
- input: string;
37
- unit: FigureUnit;
38
- value: number;
39
- }[];
40
- effects: {
41
- geometry: {
42
- added: string[];
43
- removed: string[];
44
- changed: string[];
45
- };
46
- bindingsChanged: string[];
47
- };
48
- validation: {
49
- status: string;
50
- spatial: string;
51
- collision: string;
52
- safety: string;
53
- };
54
- };
55
- apply(q: FigureEditRequest): {
56
- revision: number;
57
- inputs: Record<string, number>;
58
- evaluation: FigureCapabilityEvaluation;
59
- canUndo: boolean;
60
- canRedo: boolean;
61
- report: {
62
- baseRevision: number;
63
- origin: "ui" | "ai";
64
- changes: {
65
- before: number | undefined;
66
- kind: "set-design" | "set-state";
67
- input: string;
68
- unit: FigureUnit;
69
- value: number;
70
- }[];
71
- effects: {
72
- geometry: {
73
- added: string[];
74
- removed: string[];
75
- changed: string[];
76
- };
77
- bindingsChanged: string[];
78
- };
79
- validation: {
80
- status: string;
81
- spatial: string;
82
- collision: string;
83
- safety: string;
84
- };
85
- };
86
- };
87
- undo(q: FigureEditControl): {
88
- revision: number;
89
- inputs: Record<string, number>;
90
- evaluation: FigureCapabilityEvaluation;
91
- canUndo: boolean;
92
- canRedo: boolean;
93
- origin: "ui" | "ai";
94
- effects: {
95
- geometry: {
96
- added: string[];
97
- removed: string[];
98
- changed: string[];
99
- };
100
- bindingsChanged: string[];
101
- };
102
- };
103
- redo(q: FigureEditControl): {
104
- revision: number;
105
- inputs: Record<string, number>;
106
- evaluation: FigureCapabilityEvaluation;
107
- canUndo: boolean;
108
- canRedo: boolean;
109
- origin: "ui" | "ai";
110
- effects: {
111
- geometry: {
112
- added: string[];
113
- removed: string[];
114
- changed: string[];
115
- };
116
- bindingsChanged: string[];
117
- };
118
- };
119
- };
120
- export type FigureAuthoringSession = ReturnType<typeof createFigureAuthoringSession>;
121
- //# sourceMappingURL=authoring-session.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"authoring-session.d.ts","sourceRoot":"","sources":["../src/authoring-session.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAA;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,IAAI,GAAG,IAAI,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,sGAAsG;IACtG,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC9B;AACD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,YAAY,GAAG,WAAW,CAAA;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AACD,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,OAAO,EAAE,iBAAiB,EAAE,CAAA;CAC7B;AA6BD,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;;;;;;;eAmE7F,iBAAiB;;;;;;;;;kBAvGxB,YAAY,GAAG,WAAW;mBACzB,MAAM;kBACP,UAAU;mBACT,MAAM;;;;;;;;;;;;;;;;;aAwGF,iBAAiB;;;;;;;;;;;sBA3GtB,YAAY,GAAG,WAAW;uBACzB,MAAM;sBACP,UAAU;uBACT,MAAM;;;;;;;;;;;;;;;;;;YAkHH,iBAAiB;;;;;;;;;;;;;;;;YAYjB,iBAAiB;;;;;;;;;;;;;;;;EAa5B;AAED,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"authoring-session.js","sourceRoot":"","sources":["../src/authoring-session.ts"],"names":[],"mappings":"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"}
package/dist/carrier.d.ts DELETED
@@ -1,23 +0,0 @@
1
- import type { FigureCarrierDeclaration } from './asset-types.ts';
2
- /** The longest CARRIERTYPE code a figure may declare. */
3
- export declare const FIGURE_CARRIER_TYPE_MAX = 64;
4
- /** How CARRIERTYPE codes are compared: without the spaces around them, in upper case. */
5
- export declare function normalizeCarrierType(code: unknown): string;
6
- /** Why a value is not a carrier declaration, with the path under `path`, or null when it is. */
7
- export declare function carrierDeclarationRefusal(value: unknown, path?: string): {
8
- code: string;
9
- path: string;
10
- message: string;
11
- } | null;
12
- /** The refusal as the error it is. */
13
- export declare function checkCarrierDeclaration(value: unknown, path?: string): asserts value is FigureCarrierDeclaration;
14
- /** A declaration as stored: the code compared form, the three lengths, nothing else. */
15
- export declare function carrierDeclarationOf(value: {
16
- type: string;
17
- dimensions: {
18
- width: number;
19
- length: number;
20
- height: number;
21
- };
22
- }): FigureCarrierDeclaration;
23
- //# sourceMappingURL=carrier.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"carrier.d.ts","sourceRoot":"","sources":["../src/carrier.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAEhE,yDAAyD;AACzD,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC,yFAAyF;AACzF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAI1D;AAID,gGAAgG;AAChG,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAuBlI;AAED,sCAAsC;AACtC,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAY,GAAG,OAAO,CAAC,KAAK,IAAI,wBAAwB,CAGnH;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,wBAAwB,CAOrJ"}
package/dist/carrier.js DELETED
@@ -1,65 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- */
4
- /*
5
- * A figure that is a carrier type says so (ADR-0123): the CARRIERTYPE code a material handling system reports, and the
6
- * carrier's physical size. Both are declared on the release. The size is never read off the occupied room, which may
7
- * hold clearance and placement conditions; a figure that is not a carrier declares nothing.
8
- *
9
- * One rule for reading an asset and for the command that declares it, so a refused declaration is refused, never
10
- * dropped quietly.
11
- */
12
- import { FigureContractError } from "./contract.js";
13
- /** The longest CARRIERTYPE code a figure may declare. */
14
- export const FIGURE_CARRIER_TYPE_MAX = 64;
15
- /** How CARRIERTYPE codes are compared: without the spaces around them, in upper case. */
16
- export function normalizeCarrierType(code) {
17
- return String(code ?? '')
18
- .trim()
19
- .toUpperCase();
20
- }
21
- const positive = (v) => typeof v === 'number' && Number.isFinite(v) && v > 0;
22
- /** Why a value is not a carrier declaration, with the path under `path`, or null when it is. */
23
- export function carrierDeclarationRefusal(value, path = 'carrier') {
24
- if (!value || typeof value !== 'object' || Array.isArray(value))
25
- return { code: 'ASSET_SCHEMA', path, message: 'object required' };
26
- const given = value;
27
- for (const key of Object.keys(given))
28
- if (key !== 'type' && key !== 'dimensions')
29
- return { code: 'ASSET_SCHEMA', path, message: `unknown ${key}` };
30
- const type = given.type;
31
- if (typeof type !== 'string' || !normalizeCarrierType(type))
32
- return { code: 'CARRIER_TYPE', path: `${path}.type`, message: 'a CARRIERTYPE code is required' };
33
- if (type !== normalizeCarrierType(type))
34
- return { code: 'CARRIER_TYPE', path: `${path}.type`, message: `${type} is not written as compared; ${normalizeCarrierType(type)}` };
35
- if (type.length > FIGURE_CARRIER_TYPE_MAX)
36
- return { code: 'CARRIER_TYPE', path: `${path}.type`, message: `at most ${FIGURE_CARRIER_TYPE_MAX} characters` };
37
- const dims = given.dimensions;
38
- if (!dims || typeof dims !== 'object' || Array.isArray(dims))
39
- return { code: 'ASSET_SCHEMA', path: `${path}.dimensions`, message: 'object required' };
40
- for (const key of Object.keys(dims))
41
- if (key !== 'width' && key !== 'length' && key !== 'height')
42
- return { code: 'ASSET_SCHEMA', path: `${path}.dimensions`, message: `unknown ${key}` };
43
- for (const axis of ['width', 'length', 'height']) {
44
- const v = dims[axis];
45
- if (!positive(v))
46
- return { code: 'CARRIER_DIMENSIONS', path: `${path}.dimensions.${axis}`, message: 'a finite positive length in mm is required' };
47
- }
48
- return null;
49
- }
50
- /** The refusal as the error it is. */
51
- export function checkCarrierDeclaration(value, path = 'carrier') {
52
- const refusal = carrierDeclarationRefusal(value, path);
53
- if (refusal)
54
- throw new FigureContractError(refusal.code, refusal.path, refusal.message);
55
- }
56
- /** A declaration as stored: the code compared form, the three lengths, nothing else. */
57
- export function carrierDeclarationOf(value) {
58
- const declaration = {
59
- type: normalizeCarrierType(value?.type),
60
- dimensions: { width: value?.dimensions?.width, length: value?.dimensions?.length, height: value?.dimensions?.height }
61
- };
62
- checkCarrierDeclaration(declaration);
63
- return declaration;
64
- }
65
- //# sourceMappingURL=carrier.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"carrier.js","sourceRoot":"","sources":["../src/carrier.ts"],"names":[],"mappings":"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"}
@@ -1,15 +0,0 @@
1
- import * as dryroom from './full-dryroom.mjs'
2
- import * as conveyor from './full-conveyor.mjs'
3
- import * as robot from './full-robot.mjs'
4
- import * as forklift from './full-forklift.mjs'
5
- import {robotBinding,forkliftBindings} from './capability-samples.mjs'
6
- export function sampleAsset(kind){
7
- const modules={dryroom,conveyor,robot,forklift},sample=modules[kind]
8
- if(!sample)throw Error('unknown sample')
9
- const pair=kind==='robot'?robotBinding():kind==='forklift'?forkliftBindings():{model:sample.fullModel(),declaration:{version:'r3-capability-3',assetFrame:'world',bindings:[]}}
10
- const designInputs={},stateDefaults={}
11
- for(const i of pair.model.inputs)(i.role==='state'?stateDefaults:designInputs)[i.id]=sample.defaults[i.id]
12
- return {version:'figure-asset-1',name:sample.seed.type,document:{version:'figure-prototype-1',model:pair.model,capabilities:pair.declaration},designInputs,stateDefaults,
13
- palette:{'palette.primary':'#154473','palette.accent':'#f79c40','palette.neutral':'#96989b','palette.dark':'#27292c','palette.light':'#d6d7d9','palette.surface':'#56585b','palette.status-danger':'#f61b30','palette.status-warning':'#e68d1a','palette.status-info':'#158bde','palette.status-success':'#1cb648'},
14
- appearance:sample.seed.parts.map(p=>({target:p.name,material:structuredClone(p.material??{token:'palette.neutral'}),...(p.primitive==='cylinder'?{segments:p.segments??8}:{}),...(p.capability?{legacyCapability:structuredClone(p.capability)}:{})}))}
15
- }
@@ -1,52 +0,0 @@
1
- // Single-process, isolated disk store. Not the product database or an authorization layer.
2
- import {readFile, open, rename, unlink} from 'node:fs/promises'
3
- import {join, resolve} from 'node:path'
4
- import {randomUUID, createHash} from 'node:crypto'
5
- import {parseAsset, serializeAsset} from './asset.mjs'
6
-
7
- export class StoreError extends Error {
8
- constructor(code,message){super(message);this.code=code}
9
- }
10
- const fail=(code,message)=>{throw new StoreError(code,message)}
11
- // Shared across store handles in this process; a multi-process deployment needs database CAS.
12
- const queues=new Map()
13
- async function exclusive(key,operation){
14
- const previous=queues.get(key)||Promise.resolve()
15
- const next=previous.catch(()=>{}).then(operation);queues.set(key,next)
16
- try{return await next}finally{if(queues.get(key)===next)queues.delete(key)}
17
- }
18
- export function createAssetStore(directory){
19
- const root=resolve(directory)
20
- function file(scope,id){
21
- for(const v of [scope,id])if(typeof v!=='string'||!v.trim()||v.length>200)fail('IDENTITY','scope and asset ID required')
22
- return join(root,createHash('sha256').update(JSON.stringify([scope,id])).digest('hex')+'.json')
23
- }
24
- async function load(path,scope,id){
25
- let raw;try{raw=await readFile(path,'utf8')}catch(e){if(e.code==='ENOENT')return null;throw e}
26
- let record;try{record=JSON.parse(raw)}catch{fail('CORRUPT','stored record is not JSON')}
27
- if(record?.format!=='store-experiment-1'||record.scope!==scope||record.id!==id||typeof record.revision!=='string'||!record.revision)fail('CORRUPT','stored record identity or revision invalid')
28
- // Stored content must pass the same semantic validation as incoming content.
29
- parseAsset(record.text)
30
- return record
31
- }
32
- return {
33
- async read({scope,id}){const record=await load(file(scope,id),scope,id);if(!record)fail('NOT_FOUND','asset not found');return record},
34
- async save({scope,id,expectedRevision,text}){
35
- if(expectedRevision!==null&&(typeof expectedRevision!=='string'||!expectedRevision))fail('PRECONDITION','expectedRevision required; null means create only')
36
- const path=file(scope,id),canonical=serializeAsset(parseAsset(text))
37
- return exclusive(path,async()=>{
38
- const current=await load(path,scope,id)
39
- if((current?.revision??null)!==expectedRevision)fail('CONFLICT','asset changed; reload before saving')
40
- const record={format:'store-experiment-1',scope,id,revision:randomUUID(),text:canonical}
41
- const temporary=path+'.'+randomUUID()+'.tmp';let handle
42
- try{
43
- handle=await open(temporary,'wx',0o600);await handle.writeFile(JSON.stringify(record));await handle.sync();await handle.close();handle=null
44
- await rename(temporary,path)
45
- }finally{
46
- await handle?.close();await unlink(temporary).catch(e=>{if(e.code!=='ENOENT')throw e})
47
- }
48
- return record
49
- })
50
- }
51
- }
52
- }
@@ -1,59 +0,0 @@
1
- import {test} from 'node:test'
2
- import assert from 'node:assert/strict'
3
- import {mkdtemp,rm,readdir} from 'node:fs/promises'
4
- import {tmpdir} from 'node:os'
5
- import {join} from 'node:path'
6
- import {execFile} from 'node:child_process'
7
- import {promisify} from 'node:util'
8
- import {createAssetStore} from './asset-store.mjs'
9
- import {sampleAsset} from './asset-samples.mjs'
10
- import {serializeAsset,parseAsset} from './asset.mjs'
11
- import {createEditorWorkspace} from './editor-workspace.mjs'
12
- async function fixture(t){const dir=await mkdtemp(join(tmpdir(),'store-'));t.after(()=>rm(dir,{recursive:true,force:true}));return {dir,store:createAssetStore(dir)}}
13
- const body=()=>serializeAsset(sampleAsset('forklift'))
14
- const key={scope:'test-domain',id:'forklift'}
15
- test('disk save survives independent store handle; explicit create and scoped identity',async t=>{
16
- const {dir,store}=await fixture(t),saved=await store.save({...key,expectedRevision:null,text:body()})
17
- assert.deepEqual(await createAssetStore(dir).read(key),saved)
18
- await assert.rejects(store.read({...key,scope:'other-domain'}),e=>e.code==='NOT_FOUND')
19
- await assert.rejects(store.save({...key,expectedRevision:null,text:body()}),e=>e.code==='CONFLICT')
20
- await assert.rejects(store.save({...key,text:body()}),e=>e.code==='PRECONDITION')
21
- // Raw identifiers never become filesystem paths.
22
- await store.save({scope:'../other',id:'../../escape',expectedRevision:null,text:body()})
23
- assert.equal((await readdir(dir)).length,2)
24
- assert.ok((await readdir(dir)).every(f=>/^[0-9a-f]{64}\.json$/.test(f)))
25
- })
26
- test('two writers cannot silently overwrite; content ABA still gets new revision',async t=>{
27
- const {dir,store}=await fixture(t),a=await store.save({...key,expectedRevision:null,text:body()})
28
- const asset=parseAsset(body());asset.designInputs.forkLength=1275;const changed=serializeAsset(asset)
29
- const results=await Promise.allSettled([store,createAssetStore(dir)].map(s=>s.save({...key,expectedRevision:a.revision,text:changed})))
30
- assert.equal(results.filter(r=>r.status==='fulfilled').length,1)
31
- assert.equal(results.find(r=>r.status==='rejected').reason.code,'CONFLICT')
32
- const b=await store.read(key),c=await store.save({...key,expectedRevision:b.revision,text:body()})
33
- assert.notEqual(c.revision,a.revision)
34
- await assert.rejects(store.save({...key,expectedRevision:a.revision,text:changed}),e=>e.code==='CONFLICT')
35
- })
36
- test('invalid source leaves prior snapshot intact and produces no temporary file',async t=>{
37
- const {dir,store}=await fixture(t),a=await store.save({...key,expectedRevision:null,text:body()})
38
- await assert.rejects(store.save({...key,expectedRevision:a.revision,text:'{"version":2}'}))
39
- assert.deepEqual(await store.read(key),a);assert.equal((await readdir(dir)).length,1)
40
- })
41
- test('failed persistence does not clear editor dirty state',async t=>{
42
- const {store}=await fixture(t),original=await store.save({...key,expectedRevision:null,text:body()})
43
- const w=createEditorWorkspace(),v=w.open(original.text)
44
- w.apply({context:v.context,origin:'ui',expectedRevision:0,changes:[{kind:'set-design',input:'forkLength',unit:'mm',value:1275}]})
45
- const snapshot=w.export({context:v.context})
46
- await store.save({...key,expectedRevision:original.revision,text:body()})
47
- await assert.rejects(store.save({...key,expectedRevision:original.revision,text:snapshot.text}),e=>e.code==='CONFLICT')
48
- assert.equal(w.read().dirty,true)
49
- assert.equal(w.read().fields.find(f=>f.id==='forkLength').value,1275)
50
- })
51
- test('a separate Node process can restore the saved asset without editor memory',async t=>{
52
- const {dir,store}=await fixture(t),asset=parseAsset(body());asset.designInputs.forkLength=1275
53
- const saved=await store.save({...key,expectedRevision:null,text:serializeAsset(asset)})
54
- const script=`import {createAssetStore} from ${JSON.stringify(new URL('./asset-store.mjs',import.meta.url).href)};
55
- const record=await createAssetStore(process.argv[1]).read(${JSON.stringify(key)});
56
- console.log(JSON.stringify({revision:record.revision,length:JSON.parse(record.text).designInputs.forkLength}));`
57
- const {stdout}=await promisify(execFile)(process.execPath,['--input-type=module','-e',script,dir])
58
- assert.deepEqual(JSON.parse(stdout),{revision:saved.revision,length:1275})
59
- })
@@ -1 +0,0 @@
1
- export {compileFigureAsset as compileAsset,parseFigureAsset as parseAsset,serializeFigureAsset as serializeAsset,captureFigureAuthoredInputs as captureAuthoredInputs} from '../../src/asset.ts'