@opetope/runtime 0.1.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 (314) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +345 -0
  4. package/README.ru.md +344 -0
  5. package/dist/application-compiler-edges.d.ts +3 -0
  6. package/dist/application-compiler-edges.js +2 -0
  7. package/dist/application-compiler-edges.js.map +1 -0
  8. package/dist/application-compiler-graph.d.ts +8 -0
  9. package/dist/application-compiler-graph.js +2 -0
  10. package/dist/application-compiler-graph.js.map +1 -0
  11. package/dist/application-compiler.d.ts +116 -0
  12. package/dist/application-compiler.js +2 -0
  13. package/dist/application-compiler.js.map +1 -0
  14. package/dist/application-conditions.d.ts +18 -0
  15. package/dist/application-conditions.js +2 -0
  16. package/dist/application-conditions.js.map +1 -0
  17. package/dist/application-definition.d.ts +30 -0
  18. package/dist/application-definition.js +2 -0
  19. package/dist/application-definition.js.map +1 -0
  20. package/dist/application-error.d.ts +10 -0
  21. package/dist/application-error.js +2 -0
  22. package/dist/application-error.js.map +1 -0
  23. package/dist/application-execution.d.ts +43 -0
  24. package/dist/application-execution.js +2 -0
  25. package/dist/application-execution.js.map +1 -0
  26. package/dist/application-feature-bindings.d.ts +11 -0
  27. package/dist/application-feature-bindings.js +2 -0
  28. package/dist/application-feature-bindings.js.map +1 -0
  29. package/dist/application-feature-instance.d.ts +5 -0
  30. package/dist/application-feature-instance.js +2 -0
  31. package/dist/application-feature-instance.js.map +1 -0
  32. package/dist/application-group-order.d.ts +29 -0
  33. package/dist/application-group-order.js +2 -0
  34. package/dist/application-group-order.js.map +1 -0
  35. package/dist/application-instance-retirement.d.ts +36 -0
  36. package/dist/application-instance-retirement.js +2 -0
  37. package/dist/application-instance-retirement.js.map +1 -0
  38. package/dist/application-open-options.d.ts +29 -0
  39. package/dist/application-open-options.js +2 -0
  40. package/dist/application-open-options.js.map +1 -0
  41. package/dist/application-port-compiler.d.ts +28 -0
  42. package/dist/application-port-compiler.js +2 -0
  43. package/dist/application-port-compiler.js.map +1 -0
  44. package/dist/attachment-call-declaration.d.ts +43 -0
  45. package/dist/attachment-call-declaration.js +2 -0
  46. package/dist/attachment-call-declaration.js.map +1 -0
  47. package/dist/attachment-declaration.d.ts +68 -0
  48. package/dist/attachment-declaration.js +2 -0
  49. package/dist/attachment-declaration.js.map +1 -0
  50. package/dist/attachment-execution.d.ts +9 -0
  51. package/dist/attachment-execution.js +2 -0
  52. package/dist/attachment-execution.js.map +1 -0
  53. package/dist/attachment-retirement-scheduler.d.ts +14 -0
  54. package/dist/attachment-retirement-scheduler.js +2 -0
  55. package/dist/attachment-retirement-scheduler.js.map +1 -0
  56. package/dist/call-option-snapshot.d.ts +20 -0
  57. package/dist/call-option-snapshot.js +2 -0
  58. package/dist/call-option-snapshot.js.map +1 -0
  59. package/dist/compile-call-target-bindings.d.ts +14 -0
  60. package/dist/compile-call-target-bindings.js +2 -0
  61. package/dist/compile-call-target-bindings.js.map +1 -0
  62. package/dist/compile-module-template.d.ts +38 -0
  63. package/dist/compile-module-template.js +2 -0
  64. package/dist/compile-module-template.js.map +1 -0
  65. package/dist/condition-group-execution.d.ts +44 -0
  66. package/dist/condition-group-execution.js +2 -0
  67. package/dist/condition-group-execution.js.map +1 -0
  68. package/dist/condition-override.d.ts +28 -0
  69. package/dist/condition-override.js +2 -0
  70. package/dist/condition-override.js.map +1 -0
  71. package/dist/condition-source.d.ts +10 -0
  72. package/dist/condition-source.js +2 -0
  73. package/dist/condition-source.js.map +1 -0
  74. package/dist/condition-types.d.ts +14 -0
  75. package/dist/condition.d.ts +28 -0
  76. package/dist/condition.js +2 -0
  77. package/dist/condition.js.map +1 -0
  78. package/dist/control-registry.d.ts +56 -0
  79. package/dist/control-registry.js +2 -0
  80. package/dist/control-registry.js.map +1 -0
  81. package/dist/dynamic-scope-child.d.ts +23 -0
  82. package/dist/dynamic-scope-child.js +2 -0
  83. package/dist/dynamic-scope-child.js.map +1 -0
  84. package/dist/dynamic-scope-controller.d.ts +16 -0
  85. package/dist/dynamic-scope-controller.js +2 -0
  86. package/dist/dynamic-scope-controller.js.map +1 -0
  87. package/dist/feature-attachment-authoring-types.d.ts +51 -0
  88. package/dist/feature-attachment-lowering.d.ts +18 -0
  89. package/dist/feature-attachment-lowering.js +2 -0
  90. package/dist/feature-attachment-lowering.js.map +1 -0
  91. package/dist/feature-attachment.d.ts +45 -0
  92. package/dist/feature-attachment.js +2 -0
  93. package/dist/feature-attachment.js.map +1 -0
  94. package/dist/feature-authoring-types.d.ts +196 -0
  95. package/dist/feature-authoring.d.ts +15 -0
  96. package/dist/feature-authoring.js +2 -0
  97. package/dist/feature-authoring.js.map +1 -0
  98. package/dist/feature-body.d.ts +53 -0
  99. package/dist/feature-body.js +2 -0
  100. package/dist/feature-body.js.map +1 -0
  101. package/dist/feature-call-authority.d.ts +8 -0
  102. package/dist/feature-call-authority.js +2 -0
  103. package/dist/feature-call-authority.js.map +1 -0
  104. package/dist/feature-call-types.d.ts +39 -0
  105. package/dist/feature-call.d.ts +18 -0
  106. package/dist/feature-call.js +2 -0
  107. package/dist/feature-call.js.map +1 -0
  108. package/dist/feature-calls.d.ts +6 -0
  109. package/dist/feature-calls.js +2 -0
  110. package/dist/feature-calls.js.map +1 -0
  111. package/dist/feature-contract.d.ts +70 -0
  112. package/dist/feature-contract.js +2 -0
  113. package/dist/feature-contract.js.map +1 -0
  114. package/dist/feature-contribution-model.d.ts +38 -0
  115. package/dist/feature-contribution-model.js +2 -0
  116. package/dist/feature-contribution-model.js.map +1 -0
  117. package/dist/feature-contribution.d.ts +126 -0
  118. package/dist/feature-contribution.js +2 -0
  119. package/dist/feature-contribution.js.map +1 -0
  120. package/dist/feature-definition-api.d.ts +53 -0
  121. package/dist/feature-definition-support.d.ts +21 -0
  122. package/dist/feature-definition-support.js +2 -0
  123. package/dist/feature-definition-support.js.map +1 -0
  124. package/dist/feature-effect.d.ts +26 -0
  125. package/dist/feature-effect.js +2 -0
  126. package/dist/feature-effect.js.map +1 -0
  127. package/dist/feature-event.d.ts +32 -0
  128. package/dist/feature-event.js +2 -0
  129. package/dist/feature-event.js.map +1 -0
  130. package/dist/feature-generation.d.ts +34 -0
  131. package/dist/feature-generation.js +2 -0
  132. package/dist/feature-generation.js.map +1 -0
  133. package/dist/feature-lazy-generation.d.ts +6 -0
  134. package/dist/feature-lazy-generation.js +2 -0
  135. package/dist/feature-lazy-generation.js.map +1 -0
  136. package/dist/feature-lazy.d.ts +44 -0
  137. package/dist/feature-lazy.js +2 -0
  138. package/dist/feature-lazy.js.map +1 -0
  139. package/dist/feature-materialization-binding.d.ts +31 -0
  140. package/dist/feature-materialization-binding.js +2 -0
  141. package/dist/feature-materialization-binding.js.map +1 -0
  142. package/dist/feature-materialization-types.d.ts +45 -0
  143. package/dist/feature-model-dependencies.d.ts +23 -0
  144. package/dist/feature-model-dependencies.js +2 -0
  145. package/dist/feature-model-dependencies.js.map +1 -0
  146. package/dist/feature-model.d.ts +60 -0
  147. package/dist/feature-model.js +2 -0
  148. package/dist/feature-model.js.map +1 -0
  149. package/dist/feature-optional.d.ts +15 -0
  150. package/dist/feature-optional.js +2 -0
  151. package/dist/feature-optional.js.map +1 -0
  152. package/dist/feature-own-lowering.d.ts +22 -0
  153. package/dist/feature-own-lowering.js +2 -0
  154. package/dist/feature-own-lowering.js.map +1 -0
  155. package/dist/feature-port-binding.d.ts +6 -0
  156. package/dist/feature-port-binding.js +2 -0
  157. package/dist/feature-port-binding.js.map +1 -0
  158. package/dist/feature-port.d.ts +66 -0
  159. package/dist/feature-port.js +2 -0
  160. package/dist/feature-port.js.map +1 -0
  161. package/dist/feature-record.d.ts +6 -0
  162. package/dist/feature-record.js +2 -0
  163. package/dist/feature-record.js.map +1 -0
  164. package/dist/feature-resource.d.ts +29 -0
  165. package/dist/feature-resource.js +2 -0
  166. package/dist/feature-resource.js.map +1 -0
  167. package/dist/feature-scope-types.d.ts +35 -0
  168. package/dist/feature-scope.d.ts +29 -0
  169. package/dist/feature-scope.js +2 -0
  170. package/dist/feature-scope.js.map +1 -0
  171. package/dist/feature-stream.d.ts +37 -0
  172. package/dist/feature-stream.js +2 -0
  173. package/dist/feature-stream.js.map +1 -0
  174. package/dist/feature-timers.d.ts +14 -0
  175. package/dist/feature-timers.js +2 -0
  176. package/dist/feature-timers.js.map +1 -0
  177. package/dist/index.d.ts +19 -0
  178. package/dist/index.js +2 -0
  179. package/dist/index.js.map +1 -0
  180. package/dist/inspection-activity-protocol.d.ts +63 -0
  181. package/dist/inspection-activity.d.ts +54 -0
  182. package/dist/inspection-activity.js +2 -0
  183. package/dist/inspection-activity.js.map +1 -0
  184. package/dist/inspection-diff.d.ts +10 -0
  185. package/dist/inspection-diff.js +2 -0
  186. package/dist/inspection-diff.js.map +1 -0
  187. package/dist/inspection-module-activity.d.ts +4 -0
  188. package/dist/inspection-module-activity.js +2 -0
  189. package/dist/inspection-module-activity.js.map +1 -0
  190. package/dist/inspection-observer.d.ts +38 -0
  191. package/dist/inspection-observer.js +2 -0
  192. package/dist/inspection-observer.js.map +1 -0
  193. package/dist/inspection-plan.d.ts +33 -0
  194. package/dist/inspection-plan.js +2 -0
  195. package/dist/inspection-plan.js.map +1 -0
  196. package/dist/inspection-protocol.d.ts +333 -0
  197. package/dist/inspection-protocol.js +2 -0
  198. package/dist/inspection-protocol.js.map +1 -0
  199. package/dist/inspection-registry.d.ts +41 -0
  200. package/dist/inspection-registry.js +2 -0
  201. package/dist/inspection-registry.js.map +1 -0
  202. package/dist/inspection-session.d.ts +92 -0
  203. package/dist/inspection-session.js +2 -0
  204. package/dist/inspection-session.js.map +1 -0
  205. package/dist/inspection-snapshot.d.ts +4 -0
  206. package/dist/inspection-snapshot.js +2 -0
  207. package/dist/inspection-snapshot.js.map +1 -0
  208. package/dist/inspection-state.d.ts +91 -0
  209. package/dist/inspection-state.js +2 -0
  210. package/dist/inspection-state.js.map +1 -0
  211. package/dist/instance-demand.d.ts +31 -0
  212. package/dist/instance-demand.js +2 -0
  213. package/dist/instance-demand.js.map +1 -0
  214. package/dist/internal.d.ts +41 -0
  215. package/dist/internal.js +2 -0
  216. package/dist/internal.js.map +1 -0
  217. package/dist/keyed-scope-controller.d.ts +11 -0
  218. package/dist/keyed-scope-controller.js +2 -0
  219. package/dist/keyed-scope-controller.js.map +1 -0
  220. package/dist/model-kernel.d.ts +18 -0
  221. package/dist/model-kernel.js +2 -0
  222. package/dist/model-kernel.js.map +1 -0
  223. package/dist/module-call-context.d.ts +7 -0
  224. package/dist/module-call-context.js +2 -0
  225. package/dist/module-call-context.js.map +1 -0
  226. package/dist/module-call-runtime.d.ts +21 -0
  227. package/dist/module-call-runtime.js +2 -0
  228. package/dist/module-call-runtime.js.map +1 -0
  229. package/dist/module-generation.d.ts +57 -0
  230. package/dist/module-generation.js +2 -0
  231. package/dist/module-generation.js.map +1 -0
  232. package/dist/module-instance-types.d.ts +156 -0
  233. package/dist/module-instance.d.ts +19 -0
  234. package/dist/module-instance.js +2 -0
  235. package/dist/module-instance.js.map +1 -0
  236. package/dist/module-runtime-identity.d.ts +4 -0
  237. package/dist/module-runtime-identity.js +2 -0
  238. package/dist/module-runtime-identity.js.map +1 -0
  239. package/dist/module-scope-open.d.ts +4 -0
  240. package/dist/module-scope-open.js +2 -0
  241. package/dist/module-scope-open.js.map +1 -0
  242. package/dist/module-scope-retirement.d.ts +3 -0
  243. package/dist/module-scope-retirement.js +2 -0
  244. package/dist/module-scope-retirement.js.map +1 -0
  245. package/dist/module-template-ir.d.ts +59 -0
  246. package/dist/owner-generation-retirement.d.ts +6 -0
  247. package/dist/owner-generation-retirement.js +2 -0
  248. package/dist/owner-generation-retirement.js.map +1 -0
  249. package/dist/owner-generation-state.d.ts +123 -0
  250. package/dist/owner-generation-state.js +2 -0
  251. package/dist/owner-generation-state.js.map +1 -0
  252. package/dist/owner-generation.d.ts +16 -0
  253. package/dist/owner-generation.js +2 -0
  254. package/dist/owner-generation.js.map +1 -0
  255. package/dist/public-module-definition.d.ts +9 -0
  256. package/dist/public-module-definition.js +2 -0
  257. package/dist/public-module-definition.js.map +1 -0
  258. package/dist/public-module-instance.d.ts +6 -0
  259. package/dist/public-module-instance.js +2 -0
  260. package/dist/public-module-instance.js.map +1 -0
  261. package/dist/public-module-retirement-diagnostics.d.ts +5 -0
  262. package/dist/public-module-retirement-diagnostics.js +2 -0
  263. package/dist/public-module-retirement-diagnostics.js.map +1 -0
  264. package/dist/public-module-retirement.d.ts +3 -0
  265. package/dist/public-module-retirement.js +2 -0
  266. package/dist/public-module-retirement.js.map +1 -0
  267. package/dist/public-module-scope.d.ts +5 -0
  268. package/dist/public-module-scope.js +2 -0
  269. package/dist/public-module-scope.js.map +1 -0
  270. package/dist/public-module-state.d.ts +28 -0
  271. package/dist/public-module-state.js +2 -0
  272. package/dist/public-module-state.js.map +1 -0
  273. package/dist/public-module-types.d.ts +295 -0
  274. package/dist/public-module.d.ts +4 -0
  275. package/dist/resource-cache.d.ts +12 -0
  276. package/dist/resource-cache.js +2 -0
  277. package/dist/resource-cache.js.map +1 -0
  278. package/dist/resource-controller.d.ts +29 -0
  279. package/dist/resource-controller.js +2 -0
  280. package/dist/resource-controller.js.map +1 -0
  281. package/dist/resource-policy.d.ts +16 -0
  282. package/dist/resource-policy.js +2 -0
  283. package/dist/resource-policy.js.map +1 -0
  284. package/dist/resource-snapshot.d.ts +12 -0
  285. package/dist/resource-snapshot.js +2 -0
  286. package/dist/resource-snapshot.js.map +1 -0
  287. package/dist/resource-types.d.ts +3 -0
  288. package/dist/runtime-error-reporting.d.ts +4 -0
  289. package/dist/runtime-error-reporting.js +2 -0
  290. package/dist/runtime-error-reporting.js.map +1 -0
  291. package/dist/stream-backpressure.d.ts +18 -0
  292. package/dist/stream-backpressure.js +2 -0
  293. package/dist/stream-backpressure.js.map +1 -0
  294. package/dist/stream-cleanup.d.ts +17 -0
  295. package/dist/stream-cleanup.js +2 -0
  296. package/dist/stream-cleanup.js.map +1 -0
  297. package/dist/stream-controller-types.d.ts +51 -0
  298. package/dist/stream-controller.d.ts +5 -0
  299. package/dist/stream-controller.js +2 -0
  300. package/dist/stream-controller.js.map +1 -0
  301. package/docs/agent-guide.md +214 -0
  302. package/docs/agent-guide.ru.md +208 -0
  303. package/docs/cookbook.md +734 -0
  304. package/docs/cookbook.ru.md +729 -0
  305. package/docs/decisions.md +1437 -0
  306. package/docs/devtools.md +423 -0
  307. package/docs/devtools.ru.md +419 -0
  308. package/docs/how-it-works.md +521 -0
  309. package/docs/how-it-works.ru.md +495 -0
  310. package/docs/releases.md +78 -0
  311. package/docs/releases.ru.md +78 -0
  312. package/docs/spec.md +874 -0
  313. package/docs/spec.ru.md +884 -0
  314. package/package.json +72 -0
@@ -0,0 +1,208 @@
1
+ # Opetope: гайд для агентов и людей, пишущих код на фреймворке
2
+
3
+ Короткий, проверяемый документ: как принять решение о форме кода, что запрещено и какую ошибку вы увидите, какие
4
+ проверки запускать. Подробности в [cookbook.md](cookbook.md), устройство в [how-it-works.md](how-it-works.md),
5
+ законы в [spec.md](spec.md).
6
+
7
+ ## 1. Где что лежит
8
+
9
+ Разделяйте композицию фичи, реализации моделей и UI на отдельные слои. Пути ниже показывают структуру
10
+ `features/<f>/{integration,models,ui}`; хост владеет объявлением приложения и привязками, которые передаёт при его
11
+ открытии. Границы зависимостей действуют независимо от названий каталогов.
12
+
13
+ | Что пишете | Куда | Импортирует |
14
+ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
15
+ | контракты (`defineHostContract`, `definePort`, `defineSlot`, `defineModel`, `defineCondition`) | `features/<f>/integration/platform/*.contract.ts`, `ui/**/contracts.ts`, `slots.ts`; consumer владеет target-контрактом, фича — значением вклада | `@opetope/core`, `@opetope/runtime`, типы; `@opetope/react` для UI slot targets |
16
+ | фича (`defineFeature`) | `features/<f>/integration/platform/feature.ts(x)` | контракты, свои модели/UI, `@opetope/runtime` |
17
+ | модели (`defineModel` + фабрики) | `features/<f>/models/**` | `@opetope/core` |
18
+ | UI вкладов (`requiresModels`, хуки) | `features/<f>/ui/**` | `@opetope/core`, `@opetope/react` |
19
+ | композиция приложения и интеграция с хостом | слои bootstrap и integration приложения | `@opetope/runtime`, `@opetope/react/integration`; internal-входы только для низкоуровневой интеграции |
20
+
21
+ Оставляйте `internal`-входы и `@opetope/react/integration` в реализации рантайма, интеграции с хостом и тестах.
22
+ UI фичи и реализации моделей не должны импортировать `@opetope/runtime`, реализацию другой фичи или собственный
23
+ слой integration. Закрепите эти границы зависимостей статическими проверками проекта-хоста.
24
+
25
+ ## 2. Как выбрать форму (чеклист перед `defineFeature`)
26
+
27
+ 1. Что мне дают снаружи? Хост → `defineHostContract` + `imports`. Другая фича → `imports: { x: feature }` (жёстко) или
28
+ `optional(feature)` (может отсутствовать или выключаться). Возможность по имени → `requires: { p: port }`.
29
+ 2. Когда я живу? Всегда → без `when`. При условии → `when: [condition]`; условие объявляет хост
30
+ (`defineCondition({ id })`) или другая фича (`defineCondition({ from, id, select })`).
31
+ 3. Что я делаю? Вызовы хоста → `calls(imports.x, [...])`; свой процесс → `call({ run, lane?, once?, singleFlight?,
32
+ policy?, within })`; данные по ключу → `resource`; поток → `stream` с `latest()`; внешние события → `event`;
33
+ реакция на изменение → `effect`; подпроцесс при условии → `scope.while`; модель с состоянием → `model(Decl, { source: imports.source }, (ctx, { source }) => …)`.
34
+ 4. Что я отдаю? Другим фичам → `exports` (`Call | Readable | Resource`, поля модели, не модель). Приложению →
35
+ `provides.port`. Интерфейсу → `provides.slot/pipe/register`.
36
+ 5. UI? Только вклад в слот. Компонент объявляет per-mount модели через `requiresModels([...])`; модели `own` доступны сами.
37
+
38
+ Фича с тяжёлой реализацией пишется заголовком и телом: заголовок держит `id`, `imports`, `requires`,
39
+ `provides` как метаданные, `when` и `body: () => import(...)`, а файл тела пишет
40
+ `defineFeature.body(header, { own, exports, provides })`. Приложение и consumers импортируют только заголовок, тело
41
+ загружается при открытии экземпляра (D186, D207). `defineFeature.preload(feature)` подтягивает этот код заранее,
42
+ ничего не открывая; для фичи без тела это успешный no-op (D208).
43
+
44
+ Стадии декларации (`own` и внешняя `provides`) видят refs. Стадии экземпляра (`exports`, вложенные фабрики
45
+ вкладов и фабрики моделей) получают материализованные значения. Зависимости модели собираются readonly-записью
46
+ импортов и call refs текущей фичи, включая `requires.x`; optional-импорты сохраняют lookup-проекцию.
47
+ Для вызова модели используется `port(Port, { from: own.model, select: value => value.call })`.
48
+ `calls(imports.x, keys)` принимает методы хоста, экспортированные вызовы жёсткого импорта фичи и экспортированные
49
+ вызовы поверх `optional(feature)` — там они отвечают `CallError` `unavailable`, пока провайдера нет. Данные слабого
50
+ ребра читайте через `fromOptional(source, select, { missing })`, а не разворачивая `lookup.kind` руками (D187). У ресурсов
51
+ и стримов `target` выбирает `Readable<T | null | undefined>`, а `retention` необязателен; `scoped({ capacity })`
52
+ фиксирует LRU. Фильтр эффекта — `when(current, previous)`. Это канонические формы без алиасов (D168, D169).
53
+
54
+ Объявляйте команду через `ctx.call(options)` в модели или `call(options)` в `own`. Исполняйте существующую команду
55
+ через `context.invoke(target, input)` в её контексте исполнения, в том числе с деструктуризацией:
56
+ `run: (input, { invoke }) => invoke(deps.submit, input)`. При миграции меняйте обращения, деструктуризацию и
57
+ собственные типы контекста вместе; фабричные `call`, `calls` и существительное `Call` сохраняются (D243).
58
+ Вложенный вызов наследует отмену, авторитет и стек lane; новую политику он не выбирает.
59
+
60
+ `when` у вклада это либо `Readable<boolean>`, либо чистый синхронный предикат экземпляра —
61
+ `({ exports, imports, own, read }) => boolean`. Его `read` только записывает, от чего зависит ответ: внутри нельзя
62
+ писать, вызывать и ждать, а сам предикат выполнится снова при смене любого прочитанного источника. В этом контексте
63
+ `own` материализован: поле модели это `Readable`, а не ref декларации (D220). `pipe` объявляет обработчик
64
+ дескриптором с одним ключом — `pipe(target, { fold: (value, meta, context) => next })`, — где `context` это тот же
65
+ контекст вычисления. `fold` выполняется только на свёртке цели: ни объявление, ни `defineFeature.preload`, ни
66
+ открытие экземпляра его не вызывают, поэтому работу, которая обязана произойти при открытии, держите в `own`
67
+ (D223).
68
+
69
+ ## 3. Запрещено — и что вы увидите
70
+
71
+ | Форма | Почему нельзя | Сигнал |
72
+ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
73
+ | `exports: ({ own }) => ({ m: own.model })` | модель это запись значений | typetest/`prepare`: `Feature export m must be a Call, a Readable or a Resource.` |
74
+ | `ctx.update(foreignReadable, v)` | писатель остаётся у владельца | тип; в рантайме `TypeError: Model update accepts only state created by this model context.` |
75
+ | `onDemand(feature)` | слова нет с D105 | тип и `TypeError` в `feature-contract` |
76
+ | `optional(optional(x))` | одна обёртка | тип и `TypeError` |
77
+ | `when: 'authorized'` | только `Condition` | тип и `TypeError` |
78
+ | жёсткий импорт при `provider.when ⊄ consumer.when` | провайдер должен жить не меньше | компилятор: `… cannot depend on shorter-lived provider …; use optional for a weak edge.` |
79
+ | два провайдера одного порта | один провайдер на приложение | компилятор приложения |
80
+ | `useModel(X)` per-mount модели вклада в компоненте или хуке без `requiresModels([X])` (вложенные тоже) | тип не видит требования; owner-модели объявлять не нужно (D158) | ревью деклараций; runtime `missing` только при отсутствии модели во frame |
81
+ | `throw` для продуктового исхода команды | исходы — значения (D86) | `useCommand` покажет `lastError` только для `failed`; `cancelled` не ошибка |
82
+ | kernel-слова в публичных именах (`Module`, `Attachment`, `Executor`, `Authority`, `Owner`, `Blueprint`, `IR`) и снятые слова (`Task`, `Signal`, `Domain`, `View`, `Setup`) | словарь автора | гейт `ci:public-surface` |
83
+ | `createState`/`isCancellation` из `@opetope/core`, `useFeatureError` | сняты с безопасных входов (D142) | нет экспорта; `ctx.state`, отмену читает `useCommand` |
84
+ | ручная обёртка каждого метода хоста в `context.call` | `context.calls(source, keys, { lane })` (D143) | — |
85
+ | `when: () => readable`, `when: async () => …`, `when: ({ read }) => read(counter)` | предикат отвечает фактом, а не источником, промисом или truthy (D220) | тип; в рантайме `TypeError: Feature contribution when predicate must return a boolean.` |
86
+ | `pipe(target, handler)` или `pipe(target, () => handler)` | у `pipe` дескриптор `{ fold }` (D223) | тип; в рантайме `TypeError: Feature pipe expects a descriptor: pipe(target, { fold: … }).` |
87
+
88
+ ## 4. Ошибки: читайте `code`, не текст
89
+
90
+ `FeatureError` (`not-ready | retired | quarantined | cleanup-failed`), `CallError` (`cancelled | closed |
91
+ publication-rejected | unavailable`), `ReadableError` (`closed`), `ContributionError` (`missing | inactive | duplicate |
92
+ binding-invalid`), `ApplicationError` (`closed`), `DeclarationError` (`invalid-id`). Отмена это бренд, а не класс: `CallError` только с кодами `cancelled`/`closed`, `FeatureError` `retired`, `ContributionError` `inactive` (D138); `unavailable` и `publication-rejected` — ответы продукта, `useCommand` отдаёт их как `failed` с `lastError`. Предикат `isCancellation` живёт на `@opetope/core/internal` (D142) — автору фичи он не нужен. Закрытое состояние распространяется по производным узлам: `derive` над ушедшим провайдером бросает `closed` (D146).
93
+
94
+ Фича закрывается через `await instance.close()`. `FeatureError.retryCleanup` необязателен и появляется только
95
+ для повторяемого карантинного фронтира; перед вызовом проверьте его наличие. У других ошибок нет no-op retry.
96
+ Retry спроса принадлежит текущему источнику, а `Resource.retry()` — отдельная операция ресурса (D168, D170).
97
+
98
+ Состояние модели принадлежит создавшему контексту, даже если другая модель держит `OwnedState` того же типа.
99
+ После фенса ничего не регистрируется. Отказ фабрики должен освобождать частичный kernel, а отмена не должна
100
+ освобождать источник до физического дренажа допущенной работы. В эффектах React зависимостью служит полученный
101
+ деструктуризацией `useCommand(...).run`, а не объект со статусом. Пропсы монтирования меняются одним снимком в
102
+ layout до paint; адаптер и прямые пропсы следуют одному правилу (D170).
103
+
104
+ Для setter абсолютного значения, где нужно доставить свежий ввод, пока ждёт предыдущий, объявляйте
105
+ `policy: 'latest'` в `context.call` модели; своей политики потребитель не называет (D185, D203). Default `queue`
106
+ выполняет каждый вход по порядку и сохраняет поведение кнопок. Заменённый ожидающий вход получает `cancelled`, без
107
+ callback успеха или ошибки; не объявляйте `latest` для последовательности, где важны промежуточные операции. Lane и
108
+ физическое время жизни остаются у модели.
109
+
110
+ ## 5. Проверки перед коммитом
111
+
112
+ Из пакета: `npx tsc --noEmit`, `npm run ci:test`, `npm run ci:eslint`, `npm run ci:size-limit`.
113
+ В приложении-потребителе проверьте типы интеграции, тесты затронутых фич, production-сборку, размещение чанков и
114
+ бюджеты размера приложения его собственными командами.
115
+ Из корня: `npm run ci:eslint`, `npm run ci:oxlint`, `npm run ci:format`, `npm run ci:unused`, `npm run ci:docs`.
116
+ Из `tooling/stress`: `npm run ci:public-surface` при любом изменении публичного имени, `ci:type-stress`,
117
+ `ci:perf-memory`, `ci:inspection`.
118
+
119
+ ### Включите `@opetope/lint`
120
+
121
+ Пакет поставляет проверяемую часть законов выше, поэтому ревью не нужно проговаривать их словами. Подключите его
122
+ flat config к файлам, где живут фичи, модели и их UI:
123
+
124
+ ```js
125
+ // eslint.config.mjs
126
+ import opetope from '@opetope/lint';
127
+
128
+ export default [
129
+ {
130
+ files: ['src/**/*.{ts,tsx}'],
131
+ ...opetope.configs.recommended,
132
+ },
133
+ ];
134
+ ```
135
+
136
+ В `recommended` входят правила, которым не нужно знать о каталогах хоста. Сами правила, их фиксы и границы —
137
+ в [`../lint/README.md`](../../lint/README.ru.md).
138
+
139
+ ## 6. Меняете фреймворк, а не фичу
140
+
141
+ - Публичное имя или форма — только с compile-checked пилотом в приложении-потребителе и строкой в decision log; бюджеты
142
+ size и perf не поднимать ради сокрытия регрессии. Согласованное расширение словаря остаётся в пределах цели
143
+ public-surface и обновляет записанный бюджет вместе с решением (§5 spec).
144
+ - Файлы `core/runtime/react/src` ≤ 600 строк; делить по машине состояний, компилятору, привязке или границе хоста.
145
+ - Hot path: без `Reflect.apply`/bind/массивов аргументов на вызов, без `Object.freeze` в циклах диспетчера, без
146
+ `Error` на успешном пути; новая запись на операцию — только с измерением.
147
+ - Внутренние имена = публичные слова того же концепта; `module` — kernel-слово единицы lowering, только в `internal`.
148
+
149
+ ## 7. Ревью своего кода (семь линз коротко)
150
+
151
+ Закон §4 → где тест; authority → ничего лишнего на публичном входе; гонки → close во время open, retire во время
152
+ вызова, коммит React позже микротаска; производительность → аллокации на вызов, O(N) на событие; DX → слова §3 и
153
+ typetests на негативы, тексты ошибок называют фичу/экземпляр/вклад и подсказывают фикс; over-engineering → есть ли
154
+ у механизма продовый вызов; человек → закрытие гейта объявляет не автор.
155
+
156
+ ## Данные и команды компонента
157
+
158
+ `useModel(Declaration, (model, { read }) => ({ ... }))` выбирает данные и command consumers одним hook (D205, D214).
159
+
160
+ Результат выбора модели может быть именованным interface без index signature (D217). Результат — плоская запись данных;
161
+ arrays, functions, constructors и встроенные объекты коллекций, дат и promises не являются selection records.
162
+ Readonly record с выведенными типами преобразует authentic Call в `CommandHook`; остальные поля сохраняют свои типы.
163
+ `read(readable, project?)` читает явно, объединяет подписки на один источник и не делает автоматический Resource retain.
164
+ Поля сравниваются через `Object.is`; новый вложенный объект считается изменением. Чистый callback не вызывает hooks,
165
+ команды или side effects. Замена подписок и допуск команд происходят в commit, не в abandoned render. Ключи, aliases,
166
+ локальные статусы и `.run` следуют `useCommands`. Создание модели, feature acquire и новый scheduler не подразумеваются.
167
+ `useModel(Declaration)` по-прежнему возвращает выданную модель; структура React hooks постоянна при смене selection.
168
+ Общий hook улучшает DX, но сам по себе не гарантирует ускорение.
169
+
170
+ ## Сценарные тесты и физическая активность
171
+
172
+ `createScenario(application, options)` из `@opetope/react/testing` открывает настоящее приложение и его существующую
173
+ inspection session (D206, D215). Передайте обычные `imports`/`conditions` и принадлежащий тесту адаптер
174
+ `host.mount(Component)`, возвращающий handle с `unmount()`. Пакет не добавляет зависимость от DOM renderer или test runner.
175
+ `scenario.mount(target, { props })` использует опубликованные Slot contributions и возвращает
176
+ `{ host, updateProps, unmount }`; `host` — исходный результат renderer. Typed targets требуют `options.props`,
177
+ а targets без props опускают его, как в `Slot` (D217). Fixtures не обходят authority команд.
178
+
179
+ Синхронный конструктор возвращает `ready`, поэтому pending lazy body можно исследовать до готовности.
180
+ `waitFor(snapshot => predicate, { label, timeoutMs, pollIntervalMs })` просыпается от inspection и дополнительно
181
+ опрашивает predicates внешнего UI; `notify()` будит его после изменения управляемой fixture. По умолчанию deadline
182
+ равен 1000ms, polling predicate — 10ms. `ScenarioTimeoutError` содержит data-only snapshot, ограниченную историю и
183
+ наблюдаемые conditions, фазы feature, body load, lane blockers и удержания ресурсов. Причины внутри repository
184
+ или сети не выводятся из догадок. `getSnapshot()` и `history()` используют ту же модель наблюдения; по умолчанию
185
+ хранятся 64 снимка, activity ограничена 256 записями. Capacities — целые от 1 до 10000.
186
+ Не заменяйте predicates фиксированным числом ticks.
187
+
188
+ `close()` синхронно ставит fence admission приложения, размонтирует зарегистрированные экраны и ждёт их cleanup
189
+ вместе с physical application drain. Deadline не отменяет cleanup: последующий `close()` может дождаться того же drain.
190
+ Deadline готовности также оставляет приложение доступным для inspection и явного закрытия.
191
+ `ownership()` описывает только зарегистрированное владение runtime; при отсутствующих, stale или усечённых данных
192
+ возвращается `unknown`. Терминальный stale-снимок считается полным лишь после подтверждённого сценарием успешного
193
+ физического cleanup. Это допускает проверку нулевых счётчиков в данном scope, но не доказывает отсутствие произвольных
194
+ host/UI/GC-утечек. Успешный cleanup очищает imports приложения и внутренние ссылки на renderer. Promise отказавшего
195
+ cleanup может удерживать исходные ошибки и retry capabilities; сохранённый пользователем `mounted.host` удерживает его renderer result.
196
+
197
+ Inspection graph/frame имеют схему `/3` и optional snapshots `opetope.runtime-activity/1`. В пределах одной session
198
+ frame без `activity` сохраняет предыдущую activity; полный snapshot/reset без этого поля очищает наблюдение (D216).
199
+ Frame с `activity` заменяет предыдущую activity целиком.
200
+ Используйте согласованные версии runtime/devtools: readers `/2` отвергают новую revision. Activity указывает execution,
201
+ фактическое поколение feature, физические Calls, точных текущих lane blockers, зарегистрированные leases и попытки загрузок.
202
+ Спрос хоста и UI-модели неизвестны; у stream наблюдается state, но не физические identities загрузок. `freshness`
203
+ и `truncated` отличают полное live-наблюдение от усечённого или отключённого. Закрытая session имеет stale-снимок;
204
+ `closed: true` требует успешного физического drain приложения. Control authority и продуктовые payload не добавляются.
205
+ Размер activity ограничен capacity записей. Сбор снимка обходит зарегистрированных owners, executors и resources,
206
+ поэтому capacity не ограничивает стоимость обхода. Сбор останавливается после доказанного truncation;
207
+ idle executors могут требовать обхода, чтобы подтвердить полноту данных. Обычный call dispatch не создаёт диагностических записей при
208
+ выключенном наблюдении. Frames ограничены существующей ring capacity.