@czap/core 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 (372) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/dist/addressed-digest.d.ts +15 -0
  4. package/dist/addressed-digest.d.ts.map +1 -0
  5. package/dist/addressed-digest.js +35 -0
  6. package/dist/addressed-digest.js.map +1 -0
  7. package/dist/animation.d.ts +46 -0
  8. package/dist/animation.d.ts.map +1 -0
  9. package/dist/animation.js +70 -0
  10. package/dist/animation.js.map +1 -0
  11. package/dist/assembly.d.ts +25 -0
  12. package/dist/assembly.d.ts.map +1 -0
  13. package/dist/assembly.js +58 -0
  14. package/dist/assembly.js.map +1 -0
  15. package/dist/av-bridge.d.ts +74 -0
  16. package/dist/av-bridge.d.ts.map +1 -0
  17. package/dist/av-bridge.js +107 -0
  18. package/dist/av-bridge.js.map +1 -0
  19. package/dist/av-renderer.d.ts +56 -0
  20. package/dist/av-renderer.d.ts.map +1 -0
  21. package/dist/av-renderer.js +65 -0
  22. package/dist/av-renderer.js.map +1 -0
  23. package/dist/blend.d.ts +61 -0
  24. package/dist/blend.d.ts.map +1 -0
  25. package/dist/blend.js +100 -0
  26. package/dist/blend.js.map +1 -0
  27. package/dist/boundary.d.ts +154 -0
  28. package/dist/boundary.d.ts.map +1 -0
  29. package/dist/boundary.js +269 -0
  30. package/dist/boundary.js.map +1 -0
  31. package/dist/brands.d.ts +63 -0
  32. package/dist/brands.d.ts.map +1 -0
  33. package/dist/brands.js +31 -0
  34. package/dist/brands.js.map +1 -0
  35. package/dist/caps.d.ts +49 -0
  36. package/dist/caps.d.ts.map +1 -0
  37. package/dist/caps.js +73 -0
  38. package/dist/caps.js.map +1 -0
  39. package/dist/capsule.d.ts +77 -0
  40. package/dist/capsule.d.ts.map +1 -0
  41. package/dist/capsule.js +18 -0
  42. package/dist/capsule.js.map +1 -0
  43. package/dist/capsules/boundary-evaluate.d.ts +28 -0
  44. package/dist/capsules/boundary-evaluate.d.ts.map +1 -0
  45. package/dist/capsules/boundary-evaluate.js +117 -0
  46. package/dist/capsules/boundary-evaluate.js.map +1 -0
  47. package/dist/capsules/canonical-cbor.d.ts +13 -0
  48. package/dist/capsules/canonical-cbor.d.ts.map +1 -0
  49. package/dist/capsules/canonical-cbor.js +60 -0
  50. package/dist/capsules/canonical-cbor.js.map +1 -0
  51. package/dist/capsules/token-buffer.d.ts +24 -0
  52. package/dist/capsules/token-buffer.d.ts.map +1 -0
  53. package/dist/capsules/token-buffer.js +53 -0
  54. package/dist/capsules/token-buffer.js.map +1 -0
  55. package/dist/capture.d.ts +40 -0
  56. package/dist/capture.d.ts.map +1 -0
  57. package/dist/capture.js +10 -0
  58. package/dist/capture.js.map +1 -0
  59. package/dist/cbor.d.ts +33 -0
  60. package/dist/cbor.d.ts.map +1 -0
  61. package/dist/cbor.js +179 -0
  62. package/dist/cbor.js.map +1 -0
  63. package/dist/cell.d.ts +53 -0
  64. package/dist/cell.d.ts.map +1 -0
  65. package/dist/cell.js +83 -0
  66. package/dist/cell.js.map +1 -0
  67. package/dist/codec.d.ts +30 -0
  68. package/dist/codec.d.ts.map +1 -0
  69. package/dist/codec.js +25 -0
  70. package/dist/codec.js.map +1 -0
  71. package/dist/component.d.ts +52 -0
  72. package/dist/component.d.ts.map +1 -0
  73. package/dist/component.js +44 -0
  74. package/dist/component.js.map +1 -0
  75. package/dist/composable.d.ts +76 -0
  76. package/dist/composable.d.ts.map +1 -0
  77. package/dist/composable.js +221 -0
  78. package/dist/composable.js.map +1 -0
  79. package/dist/compositor-pool.d.ts +74 -0
  80. package/dist/compositor-pool.d.ts.map +1 -0
  81. package/dist/compositor-pool.js +119 -0
  82. package/dist/compositor-pool.js.map +1 -0
  83. package/dist/compositor.d.ts +90 -0
  84. package/dist/compositor.d.ts.map +1 -0
  85. package/dist/compositor.js +278 -0
  86. package/dist/compositor.js.map +1 -0
  87. package/dist/config.d.ts +72 -0
  88. package/dist/config.d.ts.map +1 -0
  89. package/dist/config.js +97 -0
  90. package/dist/config.js.map +1 -0
  91. package/dist/dag.d.ts +251 -0
  92. package/dist/dag.d.ts.map +1 -0
  93. package/dist/dag.js +450 -0
  94. package/dist/dag.js.map +1 -0
  95. package/dist/defaults.d.ts +45 -0
  96. package/dist/defaults.d.ts.map +1 -0
  97. package/dist/defaults.js +45 -0
  98. package/dist/defaults.js.map +1 -0
  99. package/dist/derived.d.ts +34 -0
  100. package/dist/derived.d.ts.map +1 -0
  101. package/dist/derived.js +101 -0
  102. package/dist/derived.js.map +1 -0
  103. package/dist/diagnostics.d.ts +77 -0
  104. package/dist/diagnostics.d.ts.map +1 -0
  105. package/dist/diagnostics.js +122 -0
  106. package/dist/diagnostics.js.map +1 -0
  107. package/dist/dirty.d.ts +55 -0
  108. package/dist/dirty.d.ts.map +1 -0
  109. package/dist/dirty.js +80 -0
  110. package/dist/dirty.js.map +1 -0
  111. package/dist/easing.d.ts +55 -0
  112. package/dist/easing.d.ts.map +1 -0
  113. package/dist/easing.js +291 -0
  114. package/dist/easing.js.map +1 -0
  115. package/dist/ecs.d.ts +105 -0
  116. package/dist/ecs.d.ts.map +1 -0
  117. package/dist/ecs.js +245 -0
  118. package/dist/ecs.js.map +1 -0
  119. package/dist/fnv.d.ts +14 -0
  120. package/dist/fnv.d.ts.map +1 -0
  121. package/dist/fnv.js +28 -0
  122. package/dist/fnv.js.map +1 -0
  123. package/dist/frame-budget.d.ts +73 -0
  124. package/dist/frame-budget.d.ts.map +1 -0
  125. package/dist/frame-budget.js +114 -0
  126. package/dist/frame-budget.js.map +1 -0
  127. package/dist/gen-frame.d.ts +102 -0
  128. package/dist/gen-frame.d.ts.map +1 -0
  129. package/dist/gen-frame.js +121 -0
  130. package/dist/gen-frame.js.map +1 -0
  131. package/dist/harness/arbitrary-from-schema.d.ts +28 -0
  132. package/dist/harness/arbitrary-from-schema.d.ts.map +1 -0
  133. package/dist/harness/arbitrary-from-schema.js +262 -0
  134. package/dist/harness/arbitrary-from-schema.js.map +1 -0
  135. package/dist/harness/cached-projection.d.ts +19 -0
  136. package/dist/harness/cached-projection.d.ts.map +1 -0
  137. package/dist/harness/cached-projection.js +39 -0
  138. package/dist/harness/cached-projection.js.map +1 -0
  139. package/dist/harness/index.d.ts +16 -0
  140. package/dist/harness/index.d.ts.map +1 -0
  141. package/dist/harness/index.js +15 -0
  142. package/dist/harness/index.js.map +1 -0
  143. package/dist/harness/policy-gate.d.ts +18 -0
  144. package/dist/harness/policy-gate.d.ts.map +1 -0
  145. package/dist/harness/policy-gate.js +46 -0
  146. package/dist/harness/policy-gate.js.map +1 -0
  147. package/dist/harness/pure-transform.d.ts +42 -0
  148. package/dist/harness/pure-transform.d.ts.map +1 -0
  149. package/dist/harness/pure-transform.js +76 -0
  150. package/dist/harness/pure-transform.js.map +1 -0
  151. package/dist/harness/receipted-mutation.d.ts +23 -0
  152. package/dist/harness/receipted-mutation.d.ts.map +1 -0
  153. package/dist/harness/receipted-mutation.js +52 -0
  154. package/dist/harness/receipted-mutation.js.map +1 -0
  155. package/dist/harness/scene-composition.d.ts +19 -0
  156. package/dist/harness/scene-composition.d.ts.map +1 -0
  157. package/dist/harness/scene-composition.js +47 -0
  158. package/dist/harness/scene-composition.js.map +1 -0
  159. package/dist/harness/site-adapter.d.ts +18 -0
  160. package/dist/harness/site-adapter.d.ts.map +1 -0
  161. package/dist/harness/site-adapter.js +38 -0
  162. package/dist/harness/site-adapter.js.map +1 -0
  163. package/dist/harness/state-machine.d.ts +19 -0
  164. package/dist/harness/state-machine.d.ts.map +1 -0
  165. package/dist/harness/state-machine.js +44 -0
  166. package/dist/harness/state-machine.js.map +1 -0
  167. package/dist/hlc.d.ts +99 -0
  168. package/dist/hlc.d.ts.map +1 -0
  169. package/dist/hlc.js +219 -0
  170. package/dist/hlc.js.map +1 -0
  171. package/dist/index.d.ts +104 -0
  172. package/dist/index.d.ts.map +1 -0
  173. package/dist/index.js +137 -0
  174. package/dist/index.js.map +1 -0
  175. package/dist/interpolate.d.ts +14 -0
  176. package/dist/interpolate.d.ts.map +1 -0
  177. package/dist/interpolate.js +31 -0
  178. package/dist/interpolate.js.map +1 -0
  179. package/dist/live-cell.d.ts +46 -0
  180. package/dist/live-cell.d.ts.map +1 -0
  181. package/dist/live-cell.js +154 -0
  182. package/dist/live-cell.js.map +1 -0
  183. package/dist/op.d.ts +58 -0
  184. package/dist/op.d.ts.map +1 -0
  185. package/dist/op.js +171 -0
  186. package/dist/op.js.map +1 -0
  187. package/dist/plan.d.ts +195 -0
  188. package/dist/plan.d.ts.map +1 -0
  189. package/dist/plan.js +211 -0
  190. package/dist/plan.js.map +1 -0
  191. package/dist/protocol.d.ts +33 -0
  192. package/dist/protocol.d.ts.map +1 -0
  193. package/dist/protocol.js +10 -0
  194. package/dist/protocol.js.map +1 -0
  195. package/dist/quantizer-types.d.ts +28 -0
  196. package/dist/quantizer-types.d.ts.map +1 -0
  197. package/dist/quantizer-types.js +9 -0
  198. package/dist/quantizer-types.js.map +1 -0
  199. package/dist/receipt.d.ts +294 -0
  200. package/dist/receipt.d.ts.map +1 -0
  201. package/dist/receipt.js +352 -0
  202. package/dist/receipt.js.map +1 -0
  203. package/dist/runtime-coordinator.d.ts +75 -0
  204. package/dist/runtime-coordinator.d.ts.map +1 -0
  205. package/dist/runtime-coordinator.js +149 -0
  206. package/dist/runtime-coordinator.js.map +1 -0
  207. package/dist/scheduler.d.ts +58 -0
  208. package/dist/scheduler.d.ts.map +1 -0
  209. package/dist/scheduler.js +109 -0
  210. package/dist/scheduler.js.map +1 -0
  211. package/dist/ship-capsule.d.ts +54 -0
  212. package/dist/ship-capsule.d.ts.map +1 -0
  213. package/dist/ship-capsule.js +142 -0
  214. package/dist/ship-capsule.js.map +1 -0
  215. package/dist/ship-manifest.d.ts +45 -0
  216. package/dist/ship-manifest.d.ts.map +1 -0
  217. package/dist/ship-manifest.js +175 -0
  218. package/dist/ship-manifest.js.map +1 -0
  219. package/dist/signal.d.ts +149 -0
  220. package/dist/signal.d.ts.map +1 -0
  221. package/dist/signal.js +277 -0
  222. package/dist/signal.js.map +1 -0
  223. package/dist/speculative.d.ts +67 -0
  224. package/dist/speculative.d.ts.map +1 -0
  225. package/dist/speculative.js +139 -0
  226. package/dist/speculative.js.map +1 -0
  227. package/dist/store.d.ts +39 -0
  228. package/dist/store.d.ts.map +1 -0
  229. package/dist/store.js +42 -0
  230. package/dist/store.js.map +1 -0
  231. package/dist/style.d.ts +119 -0
  232. package/dist/style.d.ts.map +1 -0
  233. package/dist/style.js +168 -0
  234. package/dist/style.js.map +1 -0
  235. package/dist/testing.d.ts +14 -0
  236. package/dist/testing.d.ts.map +1 -0
  237. package/dist/testing.js +14 -0
  238. package/dist/testing.js.map +1 -0
  239. package/dist/theme.d.ts +78 -0
  240. package/dist/theme.d.ts.map +1 -0
  241. package/dist/theme.js +109 -0
  242. package/dist/theme.js.map +1 -0
  243. package/dist/timeline.d.ts +45 -0
  244. package/dist/timeline.d.ts.map +1 -0
  245. package/dist/timeline.js +101 -0
  246. package/dist/timeline.js.map +1 -0
  247. package/dist/token-buffer.d.ts +43 -0
  248. package/dist/token-buffer.d.ts.map +1 -0
  249. package/dist/token-buffer.js +112 -0
  250. package/dist/token-buffer.js.map +1 -0
  251. package/dist/token.d.ts +107 -0
  252. package/dist/token.d.ts.map +1 -0
  253. package/dist/token.js +143 -0
  254. package/dist/token.js.map +1 -0
  255. package/dist/tuple.d.ts +16 -0
  256. package/dist/tuple.d.ts.map +1 -0
  257. package/dist/tuple.js +16 -0
  258. package/dist/tuple.js.map +1 -0
  259. package/dist/type-utils.d.ts +41 -0
  260. package/dist/type-utils.d.ts.map +1 -0
  261. package/dist/type-utils.js +10 -0
  262. package/dist/type-utils.js.map +1 -0
  263. package/dist/typed-ref.d.ts +50 -0
  264. package/dist/typed-ref.d.ts.map +1 -0
  265. package/dist/typed-ref.js +59 -0
  266. package/dist/typed-ref.js.map +1 -0
  267. package/dist/ui-quality.d.ts +50 -0
  268. package/dist/ui-quality.d.ts.map +1 -0
  269. package/dist/ui-quality.js +64 -0
  270. package/dist/ui-quality.js.map +1 -0
  271. package/dist/validation-error.d.ts +25 -0
  272. package/dist/validation-error.d.ts.map +1 -0
  273. package/dist/validation-error.js +32 -0
  274. package/dist/validation-error.js.map +1 -0
  275. package/dist/vector-clock.d.ts +46 -0
  276. package/dist/vector-clock.d.ts.map +1 -0
  277. package/dist/vector-clock.js +91 -0
  278. package/dist/vector-clock.js.map +1 -0
  279. package/dist/video.d.ts +62 -0
  280. package/dist/video.d.ts.map +1 -0
  281. package/dist/video.js +59 -0
  282. package/dist/video.js.map +1 -0
  283. package/dist/wasm-dispatch.d.ts +52 -0
  284. package/dist/wasm-dispatch.d.ts.map +1 -0
  285. package/dist/wasm-dispatch.js +204 -0
  286. package/dist/wasm-dispatch.js.map +1 -0
  287. package/dist/wasm-fallback.d.ts +19 -0
  288. package/dist/wasm-fallback.d.ts.map +1 -0
  289. package/dist/wasm-fallback.js +93 -0
  290. package/dist/wasm-fallback.js.map +1 -0
  291. package/dist/wire.d.ts +49 -0
  292. package/dist/wire.d.ts.map +1 -0
  293. package/dist/wire.js +201 -0
  294. package/dist/wire.js.map +1 -0
  295. package/dist/zap.d.ts +42 -0
  296. package/dist/zap.d.ts.map +1 -0
  297. package/dist/zap.js +172 -0
  298. package/dist/zap.js.map +1 -0
  299. package/package.json +71 -0
  300. package/src/addressed-digest.ts +48 -0
  301. package/src/animation.ts +103 -0
  302. package/src/assembly.ts +76 -0
  303. package/src/av-bridge.ts +161 -0
  304. package/src/av-renderer.ts +118 -0
  305. package/src/blend.ts +135 -0
  306. package/src/boundary.ts +363 -0
  307. package/src/brands.ts +86 -0
  308. package/src/caps.ts +100 -0
  309. package/src/capsule.ts +95 -0
  310. package/src/capsules/boundary-evaluate.ts +128 -0
  311. package/src/capsules/canonical-cbor.ts +60 -0
  312. package/src/capsules/token-buffer.ts +57 -0
  313. package/src/capture.ts +48 -0
  314. package/src/cbor.ts +199 -0
  315. package/src/cell.ts +130 -0
  316. package/src/codec.ts +39 -0
  317. package/src/component.ts +102 -0
  318. package/src/composable.ts +328 -0
  319. package/src/compositor-pool.ts +162 -0
  320. package/src/compositor.ts +387 -0
  321. package/src/config.ts +157 -0
  322. package/src/dag.ts +527 -0
  323. package/src/defaults.ts +60 -0
  324. package/src/derived.ts +164 -0
  325. package/src/diagnostics.ts +186 -0
  326. package/src/dirty.ts +101 -0
  327. package/src/easing.ts +334 -0
  328. package/src/ecs.ts +382 -0
  329. package/src/fnv.ts +31 -0
  330. package/src/frame-budget.ts +149 -0
  331. package/src/gen-frame.ts +229 -0
  332. package/src/harness/arbitrary-from-schema.ts +270 -0
  333. package/src/harness/cached-projection.ts +46 -0
  334. package/src/harness/index.ts +16 -0
  335. package/src/harness/policy-gate.ts +51 -0
  336. package/src/harness/pure-transform.ts +121 -0
  337. package/src/harness/receipted-mutation.ts +59 -0
  338. package/src/harness/scene-composition.ts +54 -0
  339. package/src/harness/site-adapter.ts +43 -0
  340. package/src/harness/state-machine.ts +49 -0
  341. package/src/hlc.ts +238 -0
  342. package/src/index.ts +274 -0
  343. package/src/interpolate.ts +37 -0
  344. package/src/live-cell.ts +199 -0
  345. package/src/op.ts +233 -0
  346. package/src/plan.ts +317 -0
  347. package/src/protocol.ts +49 -0
  348. package/src/quantizer-types.ts +29 -0
  349. package/src/receipt.ts +444 -0
  350. package/src/runtime-coordinator.ts +230 -0
  351. package/src/scheduler.ts +161 -0
  352. package/src/ship-capsule.ts +191 -0
  353. package/src/signal.ts +345 -0
  354. package/src/speculative.ts +186 -0
  355. package/src/store.ts +77 -0
  356. package/src/style.ts +249 -0
  357. package/src/testing.ts +14 -0
  358. package/src/theme.ts +153 -0
  359. package/src/timeline.ts +146 -0
  360. package/src/token-buffer.ts +151 -0
  361. package/src/token.ts +197 -0
  362. package/src/tuple.ts +19 -0
  363. package/src/type-utils.ts +48 -0
  364. package/src/typed-ref.ts +79 -0
  365. package/src/ui-quality.ts +105 -0
  366. package/src/validation-error.ts +34 -0
  367. package/src/vector-clock.ts +111 -0
  368. package/src/video.ts +106 -0
  369. package/src/wasm-dispatch.ts +300 -0
  370. package/src/wasm-fallback.ts +102 -0
  371. package/src/wire.ts +274 -0
  372. package/src/zap.ts +241 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Capsule declaration wrapping `Boundary.evaluate` as a `pureTransform`
3
+ * instance. Proves the factory kernel against an existing, well-tested
4
+ * primitive with zero-allocation hot-path discipline.
5
+ *
6
+ * Input schema is structural — the run handler aligns the random
7
+ * thresholds + states arrays into a valid Boundary before evaluating.
8
+ * This way the harness-driven property tests exercise real boundary
9
+ * shapes without requiring the schema layer to encode the
10
+ * (thresholds.length === states.length, ascending, non-empty)
11
+ * invariants directly.
12
+ *
13
+ * @module
14
+ */
15
+
16
+ import { Schema } from 'effect';
17
+ import { defineCapsule } from '../assembly.js';
18
+ import { Boundary } from '../boundary.js';
19
+
20
+ const EvaluateInputSchema = Schema.Struct({
21
+ // Random arrays — the run handler dedupes states and aligns lengths.
22
+ // We use Schema.Array (not NonEmptyArray) for compatibility with the
23
+ // edge case `length === 0`, which we handle by short-circuiting in run.
24
+ thresholds: Schema.Array(Schema.Number),
25
+ states: Schema.Array(Schema.String),
26
+ value: Schema.Number,
27
+ });
28
+ const EvaluateOutputSchema = Schema.Struct({
29
+ state: Schema.String,
30
+ matched: Schema.Boolean,
31
+ });
32
+
33
+ type EvaluateInput = {
34
+ readonly thresholds: readonly number[];
35
+ readonly states: readonly string[];
36
+ readonly value: number;
37
+ };
38
+ type EvaluateOutput = { readonly state: string; readonly matched: boolean };
39
+
40
+ /**
41
+ * Build a valid Boundary from arbitrary input and evaluate it. When the
42
+ * input cannot form a valid boundary (empty states, too few thresholds
43
+ * after dedupe), we emit `{state: '', matched: false}` so invariants
44
+ * downstream can short-circuit on `matched`.
45
+ */
46
+ function _runBoundary(input: EvaluateInput): EvaluateOutput {
47
+ // Dedupe state names and clamp to a usable count
48
+ const seenStates = new Set<string>();
49
+ const uniqueStates: string[] = [];
50
+ for (const s of input.states) {
51
+ if (!seenStates.has(s)) {
52
+ seenStates.add(s);
53
+ uniqueStates.push(s);
54
+ }
55
+ }
56
+ if (uniqueStates.length === 0) {
57
+ return { state: '', matched: false };
58
+ }
59
+
60
+ // Build strictly-ascending thresholds. If we don't have enough unique
61
+ // thresholds for the available states, trim states to fit.
62
+ const sortedThresholds = [...input.thresholds].sort((a, b) => a - b);
63
+ const ascending: number[] = [];
64
+ let prev = Number.NEGATIVE_INFINITY;
65
+ for (const t of sortedThresholds) {
66
+ if (Number.isFinite(t) && t > prev) {
67
+ ascending.push(t);
68
+ prev = t;
69
+ }
70
+ }
71
+ // Boundary.make requires at least one [threshold, state] pair.
72
+ if (ascending.length === 0) {
73
+ // Fabricate a single-anchor boundary at 0 with the first state.
74
+ const onlyState = uniqueStates[0]!;
75
+ const b = Boundary.make({
76
+ input: 'cap.boundary-evaluate',
77
+ at: [[0, onlyState]] as const,
78
+ });
79
+ const state = Boundary.evaluate(b, input.value);
80
+ return { state, matched: true };
81
+ }
82
+
83
+ const usableLen = Math.min(ascending.length, uniqueStates.length);
84
+ const pairs: Array<readonly [number, string]> = [];
85
+ for (let i = 0; i < usableLen; i++) {
86
+ pairs.push([ascending[i]!, uniqueStates[i]!] as const);
87
+ }
88
+ const b = Boundary.make({
89
+ input: 'cap.boundary-evaluate',
90
+ at: pairs as never,
91
+ });
92
+ const state = Boundary.evaluate(b, input.value);
93
+ return { state, matched: true };
94
+ }
95
+
96
+ /**
97
+ * Declared capsule for `Boundary.evaluate`. Registered in the module-level
98
+ * catalog at import time; walked by `scripts/capsule-compile.ts` during
99
+ * the gauntlet's `capsule:compile` phase.
100
+ */
101
+ export const boundaryEvaluateCapsule = defineCapsule({
102
+ _kind: 'pureTransform',
103
+ name: 'core.boundary.evaluate',
104
+ input: EvaluateInputSchema,
105
+ output: EvaluateOutputSchema,
106
+ capabilities: { reads: [], writes: [] },
107
+ invariants: [
108
+ {
109
+ name: 'state-from-input-states-when-matched',
110
+ check: (input: EvaluateInput, output: EvaluateOutput): boolean => {
111
+ // When the run handler reports `matched`, the emitted state
112
+ // must be one of the input.states (after dedupe). When unmatched,
113
+ // the invariant trivially holds.
114
+ if (!output.matched) return true;
115
+ return input.states.includes(output.state);
116
+ },
117
+ message: 'emitted state must be one of input.states',
118
+ },
119
+ {
120
+ name: 'unmatched-implies-empty-state',
121
+ check: (_input: EvaluateInput, output: EvaluateOutput): boolean => output.matched || output.state === '',
122
+ message: 'unmatched outcomes must use empty-string state',
123
+ },
124
+ ],
125
+ budgets: { p95Ms: 0.1, allocClass: 'zero' },
126
+ site: ['node', 'browser', 'worker'],
127
+ run: (input: EvaluateInput): EvaluateOutput => _runBoundary(input),
128
+ });
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Capsule declaration wrapping CanonicalCbor as a `pureTransform`. Anchors
3
+ * the content-address kernel inside the 7-arm factory so the harness can
4
+ * audit the encoder alongside boundary evaluation and token buffering.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import { Schema } from 'effect';
10
+ import { defineCapsule } from '../assembly.js';
11
+ import { CanonicalCbor } from '../cbor.js';
12
+
13
+ /**
14
+ * Declared capsule for `CanonicalCbor.encode`. Registered in the module-level
15
+ * catalog at import time; walked by the factory compiler.
16
+ */
17
+ export const canonicalCborCapsule = defineCapsule({
18
+ _kind: 'pureTransform',
19
+ name: 'core.canonical-cbor',
20
+ input: Schema.Unknown,
21
+ output: Schema.instanceOf(Uint8Array),
22
+ capabilities: { reads: [], writes: [] },
23
+ invariants: [
24
+ {
25
+ name: 'output-is-uint8array',
26
+ check: (_input: unknown, output: Uint8Array): boolean => output instanceof Uint8Array,
27
+ message: 'encoder output must be Uint8Array',
28
+ },
29
+ {
30
+ name: 'key-order-stable',
31
+ check: (input: unknown, output: Uint8Array): boolean => {
32
+ // For plain objects, re-encoding a key-permuted shallow copy must
33
+ // produce identical bytes. Cheap structural check that binds the
34
+ // capsule's intent (canonical key order) to its observable output.
35
+ if (input === null || typeof input !== 'object' || Array.isArray(input) || input instanceof Uint8Array) {
36
+ return true;
37
+ }
38
+ const keys = Object.keys(input as Record<string, unknown>);
39
+ if (keys.length < 2) return true;
40
+ // Use Object.fromEntries to build the reversed copy so dangerous keys
41
+ // like '__proto__' become own properties (not prototype assignments).
42
+ // Mutating `reversed[k] = ...` would set the prototype for k === '__proto__'
43
+ // and silently produce a different object shape than the input had.
44
+ const reversed = Object.fromEntries(
45
+ [...keys].reverse().map((k) => [k, (input as Record<string, unknown>)[k]] as const),
46
+ );
47
+ const reencoded = CanonicalCbor.encode(reversed);
48
+ if (reencoded.length !== output.length) return false;
49
+ for (let i = 0; i < output.length; i++) {
50
+ if (reencoded[i] !== output[i]) return false;
51
+ }
52
+ return true;
53
+ },
54
+ message: 'encoded output must be invariant under key permutation',
55
+ },
56
+ ],
57
+ budgets: { p95Ms: 1, allocClass: 'bounded' },
58
+ site: ['node', 'browser', 'worker', 'edge'],
59
+ run: (input: unknown): Uint8Array => CanonicalCbor.encode(input),
60
+ });
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Capsule declaration wrapping TokenBuffer as a stateMachine.
3
+ * Proves the factory kernel against a stateful LLM-token primitive
4
+ * with bounded-allocation discipline.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import { Schema } from 'effect';
10
+ import { defineCapsule } from '../assembly.js';
11
+
12
+ const TokenEventSchema = Schema.Union([
13
+ Schema.Struct({ _tag: Schema.Literal('push'), token: Schema.String }),
14
+ Schema.Struct({ _tag: Schema.Literal('flush') }),
15
+ Schema.Struct({ _tag: Schema.Literal('reset') }),
16
+ ]);
17
+
18
+ const PhaseSchema = Schema.Union([Schema.Literal('idle'), Schema.Literal('buffering'), Schema.Literal('draining')]);
19
+
20
+ const BufferStateSchema = Schema.Struct({
21
+ phase: PhaseSchema,
22
+ tokens: Schema.Array(Schema.String),
23
+ totalBytes: Schema.Number,
24
+ });
25
+
26
+ /**
27
+ * Declared capsule for TokenBuffer. Registered in the module-level
28
+ * catalog at import time; walked by the factory compiler.
29
+ */
30
+ export const tokenBufferCapsule = defineCapsule({
31
+ _kind: 'stateMachine',
32
+ name: 'core.token-buffer',
33
+ input: TokenEventSchema,
34
+ output: BufferStateSchema,
35
+ capabilities: { reads: [], writes: ['buffer.tokens'] },
36
+ invariants: [
37
+ {
38
+ name: 'phase-matches-content',
39
+ check: (_i, o) => {
40
+ const out = o as { phase: string; tokens: readonly string[] };
41
+ return out.tokens.length === 0 ? out.phase !== 'buffering' : true;
42
+ },
43
+ message: 'empty buffer cannot be in buffering phase',
44
+ },
45
+ {
46
+ name: 'totalBytes-tracks-tokens',
47
+ check: (_i, o) => {
48
+ const out = o as { tokens: readonly string[]; totalBytes: number };
49
+ const expected = out.tokens.reduce((s, t) => s + t.length, 0);
50
+ return out.totalBytes === expected;
51
+ },
52
+ message: 'totalBytes must equal sum of token byte lengths',
53
+ },
54
+ ],
55
+ budgets: { p95Ms: 0.5, allocClass: 'bounded' },
56
+ site: ['node', 'browser'],
57
+ });
package/src/capture.ts ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Capture types -- the contract between frame rendering and video encoding.
3
+ *
4
+ * `FrameCapture` is the abstraction that both WebCodecs and Remotion
5
+ * implement. VideoRenderer produces frames, FrameCapture consumes them.
6
+ *
7
+ * @module
8
+ */
9
+
10
+ import type { Millis } from './brands.js';
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Types
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /** Encoder-facing configuration: target resolution and frame rate. */
17
+ export interface CaptureConfig {
18
+ readonly width: number;
19
+ readonly height: number;
20
+ readonly fps: number;
21
+ }
22
+
23
+ /** Single pre-rendered frame handed to a {@link FrameCapture} — frame number, timestamp, and pixel source. */
24
+ export interface CaptureFrame {
25
+ readonly frame: number;
26
+ readonly timestamp: number;
27
+ readonly bitmap: ImageBitmap | OffscreenCanvas;
28
+ }
29
+
30
+ /**
31
+ * Minimal encoder contract: `init` to open the encoder, `capture` per frame,
32
+ * `finalize` to flush and return the encoded blob. Implemented by `@czap/web`
33
+ * (WebCodecs) and `@czap/remotion` (Remotion capture).
34
+ */
35
+ export interface FrameCapture {
36
+ readonly _tag: 'FrameCapture';
37
+ init(config: CaptureConfig): Promise<void>;
38
+ capture(frame: CaptureFrame): Promise<void>;
39
+ finalize(): Promise<CaptureResult>;
40
+ }
41
+
42
+ /** Encoder output returned from {@link FrameCapture}.`finalize`: the encoded blob plus codec metadata. */
43
+ export interface CaptureResult {
44
+ readonly blob: Blob;
45
+ readonly codec: string;
46
+ readonly frames: number;
47
+ readonly durationMs: Millis;
48
+ }
package/src/cbor.ts ADDED
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Canonical CBOR encoder — RFC 8949 §4.2.1 deterministic encoding.
3
+ *
4
+ * Pure encode-only path used to produce stable byte sequences for content
5
+ * addressing and idempotency hashes. Honors ADR-0003: identical inputs
6
+ * (including key-permuted plain objects) emit byte-identical Uint8Arrays
7
+ * across platforms.
8
+ *
9
+ * Rules implemented:
10
+ * - Integers (major 0/1) use shortest form. Range: [MIN_SAFE_INTEGER,
11
+ * MAX_SAFE_INTEGER]. Negative `n` encodes as `-1 - n` per spec.
12
+ * - Numbers that are not safe integers encode as float64 (major 7, simple 27).
13
+ * - Strings encode as UTF-8 with major 3 length prefix.
14
+ * - Uint8Array encodes as major 2 (byte string) with length prefix.
15
+ * - Arrays encode definite-length (major 4).
16
+ * - Plain objects encode as definite-length maps (major 5). Keys are
17
+ * sorted by their **encoded byte order** (lex on UTF-8 bytes for the
18
+ * string-keyed case) before emission. `undefined` properties are skipped.
19
+ * - `false`/`true`/`null` emit simple values 20/21/22. `undefined` is
20
+ * coerced to null (22) for JSON parity; plain-object properties whose
21
+ * value is `undefined` are skipped entirely.
22
+ *
23
+ * @module
24
+ */
25
+
26
+ const MAJOR_UNSIGNED = 0 << 5;
27
+ const MAJOR_NEGATIVE = 1 << 5;
28
+ const MAJOR_BYTES = 2 << 5;
29
+ const MAJOR_STRING = 3 << 5;
30
+ const MAJOR_ARRAY = 4 << 5;
31
+ const MAJOR_MAP = 5 << 5;
32
+ const MAJOR_SIMPLE = 7 << 5;
33
+
34
+ const SIMPLE_FALSE = 20;
35
+ const SIMPLE_TRUE = 21;
36
+ const SIMPLE_NULL = 22;
37
+ const SIMPLE_FLOAT64 = 27;
38
+
39
+ const textEncoder = new TextEncoder();
40
+
41
+ /** Internal: encode an unsigned integer head with the given major type. */
42
+ function encodeHead(major: number, value: number): Uint8Array {
43
+ if (value < 0 || !Number.isFinite(value)) {
44
+ throw new RangeError(`CanonicalCbor: head argument must be a non-negative finite integer, got ${value}`);
45
+ }
46
+ if (value < 24) {
47
+ return new Uint8Array([major | value]);
48
+ }
49
+ if (value < 0x100) {
50
+ return new Uint8Array([major | 24, value]);
51
+ }
52
+ if (value < 0x10000) {
53
+ return new Uint8Array([major | 25, (value >>> 8) & 0xff, value & 0xff]);
54
+ }
55
+ if (value < 0x100000000) {
56
+ return new Uint8Array([
57
+ major | 26,
58
+ (value >>> 24) & 0xff,
59
+ (value >>> 16) & 0xff,
60
+ (value >>> 8) & 0xff,
61
+ value & 0xff,
62
+ ]);
63
+ }
64
+ // 8-byte unsigned integer head; safe up to 2^53 - 1.
65
+ const high = Math.floor(value / 0x100000000);
66
+ const low = value >>> 0;
67
+ return new Uint8Array([
68
+ major | 27,
69
+ (high >>> 24) & 0xff,
70
+ (high >>> 16) & 0xff,
71
+ (high >>> 8) & 0xff,
72
+ high & 0xff,
73
+ (low >>> 24) & 0xff,
74
+ (low >>> 16) & 0xff,
75
+ (low >>> 8) & 0xff,
76
+ low & 0xff,
77
+ ]);
78
+ }
79
+
80
+ function concat(parts: readonly Uint8Array[]): Uint8Array {
81
+ let total = 0;
82
+ for (const p of parts) total += p.length;
83
+ const out = new Uint8Array(total);
84
+ let offset = 0;
85
+ for (const p of parts) {
86
+ out.set(p, offset);
87
+ offset += p.length;
88
+ }
89
+ return out;
90
+ }
91
+
92
+ function encodeInteger(value: number): Uint8Array {
93
+ if (value >= 0) {
94
+ return encodeHead(MAJOR_UNSIGNED, value);
95
+ }
96
+ // -1 - n form. For value = -1 → 0; value = -100 → 99; etc.
97
+ return encodeHead(MAJOR_NEGATIVE, -1 - value);
98
+ }
99
+
100
+ function encodeFloat64(value: number): Uint8Array {
101
+ const buf = new ArrayBuffer(8);
102
+ new DataView(buf).setFloat64(0, value, false /* big-endian */);
103
+ const out = new Uint8Array(9);
104
+ out[0] = MAJOR_SIMPLE | SIMPLE_FLOAT64;
105
+ out.set(new Uint8Array(buf), 1);
106
+ return out;
107
+ }
108
+
109
+ function encodeNumber(value: number): Uint8Array {
110
+ if (
111
+ Number.isInteger(value) &&
112
+ value >= Number.MIN_SAFE_INTEGER &&
113
+ value <= Number.MAX_SAFE_INTEGER
114
+ ) {
115
+ return encodeInteger(value);
116
+ }
117
+ return encodeFloat64(value);
118
+ }
119
+
120
+ function encodeString(value: string): Uint8Array {
121
+ const utf8 = textEncoder.encode(value);
122
+ return concat([encodeHead(MAJOR_STRING, utf8.length), utf8]);
123
+ }
124
+
125
+ function encodeBytes(value: Uint8Array): Uint8Array {
126
+ return concat([encodeHead(MAJOR_BYTES, value.length), value]);
127
+ }
128
+
129
+ function encodeArray(value: readonly unknown[]): Uint8Array {
130
+ const parts: Uint8Array[] = [encodeHead(MAJOR_ARRAY, value.length)];
131
+ for (const item of value) {
132
+ parts.push(_encode(item));
133
+ }
134
+ return concat(parts);
135
+ }
136
+
137
+ function compareBytes(a: Uint8Array, b: Uint8Array): number {
138
+ const len = Math.min(a.length, b.length);
139
+ for (let i = 0; i < len; i++) {
140
+ const av = a[i]!;
141
+ const bv = b[i]!;
142
+ if (av !== bv) return av - bv;
143
+ }
144
+ return a.length - b.length;
145
+ }
146
+
147
+ function encodeObject(value: Record<string, unknown>): Uint8Array {
148
+ // Skip undefined values to match JSON semantics.
149
+ const keys = Object.keys(value).filter((k) => value[k] !== undefined);
150
+ const pairs: { keyBytes: Uint8Array; valueBytes: Uint8Array }[] = [];
151
+ for (const key of keys) {
152
+ pairs.push({
153
+ keyBytes: encodeString(key),
154
+ valueBytes: _encode(value[key]),
155
+ });
156
+ }
157
+ // RFC 8949 §4.2.1: sort by encoded-key byte sequence, lexicographically.
158
+ pairs.sort((p, q) => compareBytes(p.keyBytes, q.keyBytes));
159
+
160
+ const parts: Uint8Array[] = [encodeHead(MAJOR_MAP, pairs.length)];
161
+ for (const pair of pairs) {
162
+ parts.push(pair.keyBytes);
163
+ parts.push(pair.valueBytes);
164
+ }
165
+ return concat(parts);
166
+ }
167
+
168
+ const _encode = (value: unknown): Uint8Array => {
169
+ if (value === null || value === undefined) {
170
+ return new Uint8Array([MAJOR_SIMPLE | SIMPLE_NULL]);
171
+ }
172
+ if (typeof value === 'boolean') {
173
+ return new Uint8Array([MAJOR_SIMPLE | (value ? SIMPLE_TRUE : SIMPLE_FALSE)]);
174
+ }
175
+ if (typeof value === 'number') {
176
+ return encodeNumber(value);
177
+ }
178
+ if (typeof value === 'string') {
179
+ return encodeString(value);
180
+ }
181
+ if (value instanceof Uint8Array) {
182
+ return encodeBytes(value);
183
+ }
184
+ if (Array.isArray(value)) {
185
+ return encodeArray(value);
186
+ }
187
+ if (typeof value === 'object') {
188
+ return encodeObject(value as Record<string, unknown>);
189
+ }
190
+ throw new TypeError(`CanonicalCbor: unsupported value type ${typeof value}`);
191
+ };
192
+
193
+ /** Canonical CBOR encoder namespace (ADR-0001 pattern). */
194
+ export const CanonicalCbor = { encode: _encode } as const;
195
+
196
+ export declare namespace CanonicalCbor {
197
+ /** Output type — raw CBOR bytes per RFC 8949 §4.2.1. */
198
+ export type Encoded = Uint8Array;
199
+ }
package/src/cell.ts ADDED
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Cell<T> -- writable reactive primitive.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import type { Scope } from 'effect';
8
+ import { Effect, Stream, SubscriptionRef, Semaphore } from 'effect';
9
+ import { tupleMap } from './tuple.js';
10
+
11
+ interface CellShape<T> {
12
+ readonly _tag: 'Cell';
13
+ readonly ref: SubscriptionRef.SubscriptionRef<T>;
14
+ readonly changes: Stream.Stream<T>;
15
+ readonly get: Effect.Effect<T>;
16
+ set(value: T): Effect.Effect<void>;
17
+ update(f: (current: T) => T): Effect.Effect<void>;
18
+ }
19
+
20
+ const _make = <T>(initial: T): Effect.Effect<CellShape<T>> =>
21
+ Effect.gen(function* () {
22
+ const ref = yield* SubscriptionRef.make(initial);
23
+
24
+ return {
25
+ _tag: 'Cell' as const,
26
+ ref,
27
+ changes: SubscriptionRef.changes(ref),
28
+ get: SubscriptionRef.get(ref),
29
+ set: (value: T) => SubscriptionRef.set(ref, value),
30
+ update: (f: (current: T) => T) => SubscriptionRef.update(ref, f),
31
+ };
32
+ });
33
+
34
+ const _fromStream = <T>(initial: T, source: Stream.Stream<T>): Effect.Effect<CellShape<T>, never, Scope.Scope> =>
35
+ Effect.gen(function* () {
36
+ const cell = yield* _make(initial);
37
+
38
+ yield* Effect.forkScoped(Stream.runForEach(source, (value) => cell.set(value)));
39
+
40
+ return cell;
41
+ });
42
+
43
+ /**
44
+ * Read all values from a tuple of cells, preserving the tuple type `T`.
45
+ *
46
+ * Sanctioned single cast site for Cell combinators. Two type-system gaps force
47
+ * this containment:
48
+ * 1. `tupleMap`'s callback signature collapses to `U = Effect<T[number]>`,
49
+ * losing the per-element `Effect<T[K]>` relationship.
50
+ * 2. `Effect.all`'s tuple overload returns a mapped-tuple result
51
+ * `{ -readonly [K in keyof ...]: _A }` that TypeScript cannot fold back
52
+ * to the input tuple type `T` (`T` could be instantiated with an
53
+ * arbitrary subtype per the structural contravariance rules).
54
+ *
55
+ * The runtime behavior is provably correct: `tupleMap` is total and order-
56
+ * preserving, `Effect.all` with an array input preserves positional order and
57
+ * arity, so the resulting values are `T` by construction.
58
+ */
59
+ export const readAllCellValues = <T extends readonly unknown[]>(
60
+ cells: { readonly [K in keyof T]: CellShape<T[K]> },
61
+ ): Effect.Effect<T> => {
62
+ const gets = tupleMap(cells, (cell) => cell.get);
63
+ return Effect.all(gets, { concurrency: 'unbounded' }) as unknown as Effect.Effect<T>;
64
+ };
65
+
66
+ const _all = <const T extends readonly unknown[]>(
67
+ cells: { readonly [K in keyof T]: CellShape<T[K]> },
68
+ ): Effect.Effect<CellShape<T>, never, Scope.Scope> => {
69
+ const readAll = readAllCellValues(cells);
70
+
71
+ return Effect.gen(function* () {
72
+ const values = yield* readAll;
73
+ const combined = yield* _make(values);
74
+ const sem = Semaphore.makeUnsafe(1);
75
+
76
+ yield* Effect.forkScoped(
77
+ Effect.gen(function* () {
78
+ const changeStreams = tupleMap(cells, (cell) => cell.changes);
79
+ const updates = changeStreams.map((changes) =>
80
+ Stream.runForEach(changes, () =>
81
+ Semaphore.withPermits(
82
+ sem,
83
+ 1,
84
+ )(
85
+ Effect.gen(function* () {
86
+ const newValues = yield* readAll;
87
+ yield* combined.set(newValues);
88
+ }),
89
+ ),
90
+ ),
91
+ );
92
+ yield* Effect.all(updates, { concurrency: 'unbounded' });
93
+ }),
94
+ );
95
+
96
+ return combined;
97
+ });
98
+ };
99
+
100
+ const _map = <T, U>(cell: CellShape<T>, fn: (value: T) => U): Effect.Effect<CellShape<U>, never, Scope.Scope> =>
101
+ Effect.gen(function* () {
102
+ const initialValue = yield* cell.get;
103
+ const mappedInitial = fn(initialValue);
104
+ const mapped = yield* _make(mappedInitial);
105
+
106
+ yield* Effect.forkScoped(Stream.runForEach(cell.changes, (value) => mapped.set(fn(value))));
107
+
108
+ return mapped;
109
+ });
110
+
111
+ /**
112
+ * Cell — mutable reactive primitive backed by `SubscriptionRef`.
113
+ * The workhorse of czap's reactive graph: `get` for a snapshot, `set` to
114
+ * push, `changes` for the stream of subsequent values.
115
+ */
116
+ export const Cell = {
117
+ /** Build a cell with an initial value. */
118
+ make: _make,
119
+ /** Seed a cell with an initial value and mirror every stream emission into it. */
120
+ fromStream: _fromStream,
121
+ /** Tuple-combine cells into a single cell of their current values. */
122
+ all: _all,
123
+ /** Scoped `map` — derive a new cell by applying `fn` to every emission. */
124
+ map: _map,
125
+ };
126
+
127
+ export declare namespace Cell {
128
+ /** Structural shape of a {@link Cell}: `_tag`, `get`, `set`, `changes`. */
129
+ export type Shape<T> = CellShape<T>;
130
+ }
package/src/codec.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Codec -- Effect Schema codec builder.
3
+ *
4
+ * Wraps Effect Schema into a typed codec with encode/decode methods.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import type { Effect } from 'effect';
10
+ import { Schema } from 'effect';
11
+
12
+ interface CodecShape<A, I = A> {
13
+ readonly schema: Schema.Codec<A, I>;
14
+ encode(value: A): Effect.Effect<I, Schema.SchemaError>;
15
+ decode(input: I): Effect.Effect<A, Schema.SchemaError>;
16
+ }
17
+
18
+ function _make<A, I>(schema: Schema.Codec<A, I>): CodecShape<A, I> {
19
+ return {
20
+ schema,
21
+ encode: (value: A) => Schema.encodeEffect(schema)(value),
22
+ decode: (input: I) => Schema.decodeEffect(schema)(input),
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Codec — typed encode/decode wrapper over `effect`'s `Schema.Codec`.
28
+ * Gives a single call site for schema-driven validation so consumers don't
29
+ * import `Schema.encodeEffect`/`decodeEffect` directly.
30
+ */
31
+ export const Codec = {
32
+ /** Wrap a `Schema.Codec` in the {@link Codec.Shape} facade. */
33
+ make: _make,
34
+ };
35
+
36
+ export declare namespace Codec {
37
+ /** Structural shape of a codec: underlying schema plus `encode` / `decode` Effects. */
38
+ export type Shape<A, I = A> = CodecShape<A, I>;
39
+ }