@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,46 @@
1
+ /**
2
+ * Harness template for the `cachedProjection` assembly arm.
3
+ *
4
+ * Cached projections derive an output from a source via a deterministic
5
+ * pipeline with cache invalidation tied to source content addresses.
6
+ * Without a `derive(source)` channel on the contract the harness can't
7
+ * exercise cache-hit equality or invalidation, so each case is emitted
8
+ * as `it.skip` rather than a vacuous placeholder.
9
+ *
10
+ * @module
11
+ */
12
+
13
+ import type { CapsuleDef } from '../assembly.js';
14
+ import type { HarnessOutput } from './pure-transform.js';
15
+
16
+ /**
17
+ * Generate the test + bench file contents for a `cachedProjection` capsule.
18
+ * Emits `it.skip` placeholders for cache-hit and invalidation tests.
19
+ */
20
+ export function generateCachedProjection(
21
+ cap: CapsuleDef<'cachedProjection', unknown, unknown, unknown>,
22
+ ): HarnessOutput {
23
+ const testFile = `// GENERATED — do not edit by hand
24
+ import { describe, it } from 'vitest';
25
+
26
+ describe('${cap.name}', () => {
27
+ it.skip('cache hit: identical source yields the same derived output', () => {
28
+ // TODO(harness): needs cap.derive handler + content-addressed source.
29
+ });
30
+
31
+ it.skip('invalidation: source change produces new cache entry', () => {
32
+ // TODO(harness): same — needs cap.derive.
33
+ });
34
+ });
35
+ `;
36
+
37
+ const benchFile = `// GENERATED — do not edit by hand
38
+ import { bench } from 'vitest';
39
+
40
+ bench('${cap.name} — decode throughput', () => {
41
+ // decode a canonical source, measure p95 vs budget (${cap.budgets.p95Ms ?? 'n/a'}ms)
42
+ }, { time: 500 });
43
+ `;
44
+
45
+ return { testFile, benchFile };
46
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Harness — per-arm templates that emit test + bench + audit files
3
+ * from a capsule declaration. Each arm has its own generator.
4
+ *
5
+ * @module
6
+ */
7
+
8
+ export { generatePureTransform } from './pure-transform.js';
9
+ export type { HarnessOutput, HarnessContext } from './pure-transform.js';
10
+ export { ArbitraryFromSchema, schemaToArbitrary, UnsupportedSchemaError } from './arbitrary-from-schema.js';
11
+ export { generateReceiptedMutation } from './receipted-mutation.js';
12
+ export { generateStateMachine } from './state-machine.js';
13
+ export { generateSiteAdapter } from './site-adapter.js';
14
+ export { generatePolicyGate } from './policy-gate.js';
15
+ export { generateCachedProjection } from './cached-projection.js';
16
+ export { generateSceneComposition } from './scene-composition.js';
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Harness template for the `policyGate` assembly arm.
3
+ *
4
+ * Policy gates resolve allow/deny against typed subjects. Without a
5
+ * `decide(subject)` channel on the capsule contract the harness can't
6
+ * exercise allow/deny branches or check reason chains, so each case is
7
+ * emitted as `it.skip` rather than a vacuous placeholder.
8
+ *
9
+ * @module
10
+ */
11
+
12
+ import type { CapsuleDef } from '../assembly.js';
13
+ import type { HarnessOutput } from './pure-transform.js';
14
+
15
+ /**
16
+ * Generate the test + bench file contents for a `policyGate` capsule.
17
+ * Emits `it.skip` placeholders for allow / deny / reason-chain coverage.
18
+ */
19
+ export function generatePolicyGate(cap: CapsuleDef<'policyGate', unknown, unknown, unknown>): HarnessOutput {
20
+ const testFile = `// GENERATED — do not edit by hand
21
+ import { describe, it } from 'vitest';
22
+
23
+ describe('${cap.name}', () => {
24
+ it.skip('allow branch: a subject meeting the policy resolves to allow', () => {
25
+ // TODO(harness): needs cap.decide handler to drive subject -> outcome.
26
+ });
27
+
28
+ it.skip('deny branch: a subject failing the policy resolves to deny', () => {
29
+ // TODO(harness): same — needs cap.decide.
30
+ });
31
+
32
+ it.skip('reason chain present on every decision', () => {
33
+ // TODO(harness): same — needs cap.decide and a typed reasons schema.
34
+ });
35
+
36
+ it.skip('no silent deny: every deny has a typed reason code', () => {
37
+ // TODO(harness): same — needs reasons enum on the contract.
38
+ });
39
+ });
40
+ `;
41
+
42
+ const benchFile = `// GENERATED — do not edit by hand
43
+ import { bench } from 'vitest';
44
+
45
+ bench('${cap.name}', () => {
46
+ // policy decision with a canonical fixture
47
+ }, { time: 500 });
48
+ `;
49
+
50
+ return { testFile, benchFile };
51
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Harness template for the `pureTransform` assembly arm.
3
+ *
4
+ * Emits a property test per declared invariant: derives a fast-check
5
+ * arbitrary from the capsule's input schema (`schemaToArbitrary`),
6
+ * invokes the capsule's `run` handler against each sample, and asserts
7
+ * the invariant `check(input, output)` holds.
8
+ *
9
+ * If the capsule does not export a `run` handler the test is emitted as
10
+ * `it.skip` with a TODO comment — vacuous `() => true` placeholders are
11
+ * banned (per memory: "no vanity tests, real APIs, deterministic
12
+ * assertions").
13
+ *
14
+ * @module
15
+ */
16
+ import type { CapsuleDef } from '../assembly.js';
17
+
18
+ /** Emitted file contents for a capsule harness (test + bench pair). */
19
+ export interface HarnessOutput {
20
+ readonly testFile: string;
21
+ readonly benchFile: string;
22
+ }
23
+
24
+ /**
25
+ * Optional metadata the compile-time driver passes to harness templates so
26
+ * the generated test file can `import` the real capsule binding from its
27
+ * source file. When `bindingImport` is undefined, the harness emits an
28
+ * `it.skip` placeholder rather than a vacuous test.
29
+ */
30
+ export interface HarnessContext {
31
+ /** ESM-style import specifier (with `.js` extension) for the test file. */
32
+ readonly bindingImport?: string;
33
+ /** Exported binding name to import from `bindingImport`. */
34
+ readonly bindingName?: string;
35
+ /** Import specifier for `schemaToArbitrary`, default to source path. */
36
+ readonly arbitraryImport?: string;
37
+ }
38
+
39
+ const DEFAULT_ARBITRARY_IMPORT = '../../packages/core/src/harness/arbitrary-from-schema.js';
40
+
41
+ /**
42
+ * Generate the test + bench file contents for a `pureTransform` capsule.
43
+ * The emitted files are strings; the repo compiler writes them to
44
+ * `tests/generated/<name>.{test,bench}.ts`.
45
+ */
46
+ export function generatePureTransform(
47
+ cap: CapsuleDef<'pureTransform', unknown, unknown, unknown>,
48
+ ctx: HarnessContext = {},
49
+ ): HarnessOutput {
50
+ const arbitraryImport = ctx.arbitraryImport ?? DEFAULT_ARBITRARY_IMPORT;
51
+
52
+ if (ctx.bindingImport === undefined || ctx.bindingName === undefined) {
53
+ // No real binding wired — emit honest skip per task constraint.
54
+ const testFile = `// GENERATED — do not edit by hand
55
+ import { describe, it } from 'vitest';
56
+
57
+ describe('${cap.name}', () => {
58
+ it.skip('invariants under random input (no binding wired)', () => {
59
+ // TODO(harness): no capsule binding import wired by capsule-compile.
60
+ // Add bindingImport + bindingName to the manifest entry to enable.
61
+ });
62
+ });
63
+ `;
64
+ const benchFile = `// GENERATED — do not edit by hand
65
+ import { bench } from 'vitest';
66
+
67
+ bench('${cap.name}', () => {
68
+ // handler invocation with a canonical fixture
69
+ }, { time: 500 });
70
+ `;
71
+ return { testFile, benchFile };
72
+ }
73
+
74
+ const testFile = `// GENERATED — do not edit by hand
75
+ import { describe, it } from 'vitest';
76
+ import * as fc from 'fast-check';
77
+ import { ${ctx.bindingName} } from '${ctx.bindingImport}';
78
+ import { schemaToArbitrary, UnsupportedSchemaError } from '${arbitraryImport}';
79
+
80
+ describe('${cap.name}', () => {
81
+ const cap = ${ctx.bindingName};
82
+ let arb: fc.Arbitrary<unknown>;
83
+ let arbError: unknown;
84
+ try {
85
+ arb = schemaToArbitrary(cap.input as never) as fc.Arbitrary<unknown>;
86
+ } catch (err) {
87
+ arbError = err;
88
+ }
89
+ if (cap.run === undefined || arbError !== undefined) {
90
+ it.skip(
91
+ arbError instanceof UnsupportedSchemaError
92
+ ? \`invariants — input schema not arbitrary-derivable (\${arbError.message})\`
93
+ : 'invariants — capsule has no run handler',
94
+ () => {},
95
+ );
96
+ } else {
97
+ for (const inv of cap.invariants) {
98
+ it(\`invariant: \${inv.name}\`, () => {
99
+ fc.assert(
100
+ fc.property(arb, (input) => {
101
+ const output = cap.run!(input as never);
102
+ return inv.check(input as never, output as never);
103
+ }),
104
+ { numRuns: 100 },
105
+ );
106
+ });
107
+ }
108
+ }
109
+ });
110
+ `;
111
+
112
+ const benchFile = `// GENERATED — do not edit by hand
113
+ import { bench } from 'vitest';
114
+
115
+ bench('${cap.name}', () => {
116
+ // handler invocation with a canonical fixture
117
+ }, { time: 500 });
118
+ `;
119
+
120
+ return { testFile, benchFile };
121
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Harness template for the `receiptedMutation` assembly arm.
3
+ *
4
+ * Receipted mutations have side effects, so the harness can't drive them
5
+ * with random inputs and assert generic invariants. Each test case is
6
+ * emitted as `it.skip` with a TODO until the arm acquires a typed
7
+ * runtime invocation channel.
8
+ *
9
+ * Per memory: "no vanity tests" — emitting a `() => true` placeholder
10
+ * pretending to verify behavior is worse than skipping honestly.
11
+ *
12
+ * @module
13
+ */
14
+
15
+ import type { CapsuleDef } from '../assembly.js';
16
+ import type { HarnessOutput } from './pure-transform.js';
17
+
18
+ /**
19
+ * Generate the test + bench file contents for a `receiptedMutation` capsule.
20
+ * Emits `it.skip` placeholders covering contract shape, idempotency, audit
21
+ * receipt, and fault reachability — each carries a TODO naming the
22
+ * invocation channel it would need.
23
+ */
24
+ export function generateReceiptedMutation(
25
+ cap: CapsuleDef<'receiptedMutation', unknown, unknown, unknown>,
26
+ ): HarnessOutput {
27
+ const testFile = `// GENERATED — do not edit by hand
28
+ import { describe, it } from 'vitest';
29
+
30
+ describe('${cap.name}', () => {
31
+ it.skip('contract shape: input and output decode/encode round-trip', () => {
32
+ // TODO(harness): wire schema round-trip via cap.input / cap.output.
33
+ });
34
+
35
+ it.skip('is idempotent: two identical inputs produce equivalent receipts', () => {
36
+ // TODO(harness): receipted mutations need a runtime channel to invoke
37
+ // — until cap exposes a typed mutate handler, skip rather than fake.
38
+ });
39
+
40
+ it.skip('emits audit receipt with declared capabilities', () => {
41
+ // TODO(harness): same — needs runtime channel to read emitted receipts.
42
+ });
43
+
44
+ it.skip('fault injection: declared faults are reachable', () => {
45
+ // TODO(harness): faults table not yet on the capsule contract.
46
+ });
47
+ });
48
+ `;
49
+
50
+ const benchFile = `// GENERATED — do not edit by hand
51
+ import { bench } from 'vitest';
52
+
53
+ bench('${cap.name}', () => {
54
+ // mutation invocation with a canonical fixture
55
+ }, { time: 500 });
56
+ `;
57
+
58
+ return { testFile, benchFile };
59
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Harness template for the `sceneComposition` assembly arm.
3
+ *
4
+ * Scene composition tests need a deterministic frame-stream channel
5
+ * (`compileScene` + `renderFrame`) on the capsule contract to drive
6
+ * determinism, sync-accuracy, per-frame budget, and invariant
7
+ * preservation. Without that channel each case is emitted as `it.skip`.
8
+ *
9
+ * @module
10
+ */
11
+
12
+ import type { CapsuleDef } from '../assembly.js';
13
+ import type { HarnessOutput } from './pure-transform.js';
14
+
15
+ /**
16
+ * Generate the test + bench file contents for a `sceneComposition` capsule.
17
+ * Emits `it.skip` placeholders for determinism, sync, budget, and
18
+ * invariant-preservation cases.
19
+ */
20
+ export function generateSceneComposition(
21
+ cap: CapsuleDef<'sceneComposition', unknown, unknown, unknown>,
22
+ ): HarnessOutput {
23
+ const testFile = `// GENERATED — do not edit by hand
24
+ import { describe, it } from 'vitest';
25
+
26
+ describe('${cap.name}', () => {
27
+ it.skip('determinism: identical seed produces identical frame stream across 3 runs', () => {
28
+ // TODO(harness): needs cap.compile + cap.renderFrame on the contract.
29
+ });
30
+
31
+ it.skip('sync accuracy: audio and video frame timestamps align within +/- 1ms', () => {
32
+ // TODO(harness): same — needs typed frame stream.
33
+ });
34
+
35
+ it.skip('per-frame budget: p95 frame time below declared budget (${cap.budgets.p95Ms ?? 'n/a'}ms)', () => {
36
+ // TODO(harness): needs cap.renderFrame to time individual frames.
37
+ });
38
+
39
+ it.skip('invariant preservation: every declared scene invariant holds across playback', () => {
40
+ // TODO(harness): same — needs frame walker.
41
+ });
42
+ });
43
+ `;
44
+
45
+ const benchFile = `// GENERATED — do not edit by hand
46
+ import { bench } from 'vitest';
47
+
48
+ bench('${cap.name} — full playback', () => {
49
+ // render full scene duration, measure total wall-clock
50
+ }, { time: 2000 });
51
+ `;
52
+
53
+ return { testFile, benchFile };
54
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Harness template for the `siteAdapter` assembly arm.
3
+ *
4
+ * Site adapters convert between native host objects and czap representations.
5
+ * Without typed `toCzap` / `fromCzap` channels on the capsule contract the
6
+ * harness can't drive round-trip equality, so each case is emitted as
7
+ * `it.skip` rather than a vacuous placeholder.
8
+ *
9
+ * @module
10
+ */
11
+
12
+ import type { CapsuleDef } from '../assembly.js';
13
+ import type { HarnessOutput } from './pure-transform.js';
14
+
15
+ /**
16
+ * Generate the test + bench file contents for a `siteAdapter` capsule.
17
+ * Emits `it.skip` placeholders for round-trip and host-capability tests.
18
+ */
19
+ export function generateSiteAdapter(cap: CapsuleDef<'siteAdapter', unknown, unknown, unknown>): HarnessOutput {
20
+ const testFile = `// GENERATED — do not edit by hand
21
+ import { describe, it } from 'vitest';
22
+
23
+ describe('${cap.name}', () => {
24
+ it.skip('round-trip equality: native -> czap -> native preserves structure', () => {
25
+ // TODO(harness): needs cap.toCzap / cap.fromCzap on the contract.
26
+ });
27
+
28
+ it.skip('host capability matrix: each declared site supports the adapter', () => {
29
+ // TODO(harness): needs per-site dispatcher to invoke under each runtime.
30
+ });
31
+ });
32
+ `;
33
+
34
+ const benchFile = `// GENERATED — do not edit by hand
35
+ import { bench } from 'vitest';
36
+
37
+ bench('${cap.name}', () => {
38
+ // adapter call with a canonical native fixture
39
+ }, { time: 500 });
40
+ `;
41
+
42
+ return { testFile, benchFile };
43
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Harness template for the `stateMachine` assembly arm.
3
+ *
4
+ * State machines need a typed `step(state, event)` channel to drive
5
+ * randomized event sequences and check invariants at every step. The
6
+ * capsule contract doesn't yet expose one, so each case is emitted as
7
+ * `it.skip` rather than a vacuous `() => true` placeholder.
8
+ *
9
+ * @module
10
+ */
11
+
12
+ import type { CapsuleDef } from '../assembly.js';
13
+ import type { HarnessOutput } from './pure-transform.js';
14
+
15
+ /**
16
+ * Generate the test + bench file contents for a `stateMachine` capsule.
17
+ * Emits `it.skip` placeholders covering illegal transitions, replay, and
18
+ * invariant preservation — each carries a TODO naming the missing handler.
19
+ */
20
+ export function generateStateMachine(cap: CapsuleDef<'stateMachine', unknown, unknown, unknown>): HarnessOutput {
21
+ const testFile = `// GENERATED — do not edit by hand
22
+ import { describe, it } from 'vitest';
23
+
24
+ describe('${cap.name}', () => {
25
+ it.skip('rejects every illegal transition', () => {
26
+ // TODO(harness): needs cap.transitions table + cap.step handler.
27
+ });
28
+
29
+ it.skip('replays deterministically from an event log', () => {
30
+ // TODO(harness): needs cap.step + cap.initialState.
31
+ });
32
+
33
+ it.skip('invariant holds across random event paths', () => {
34
+ // TODO(harness): same — schemaToArbitrary on cap.input would feed
35
+ // events, but invariants need (state, event) → state to be checkable.
36
+ });
37
+ });
38
+ `;
39
+
40
+ const benchFile = `// GENERATED — do not edit by hand
41
+ import { bench } from 'vitest';
42
+
43
+ bench('${cap.name}', () => {
44
+ // state-machine step with a canonical event
45
+ }, { time: 500 });
46
+ `;
47
+
48
+ return { testFile, benchFile };
49
+ }
package/src/hlc.ts ADDED
@@ -0,0 +1,238 @@
1
+ /**
2
+ * HLC -- Hybrid Logical Clock.
3
+ *
4
+ * Pure functions + Effect-based managed clock.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import type { Effect } from 'effect';
10
+ import { Ref } from 'effect';
11
+
12
+ // Hybrid Logical Clock: physical wall-clock + logical counter for causal ordering. DagPosition encodes (timestamp, counter, nodeId) for DAG vertex identity.
13
+
14
+ interface HLCShape {
15
+ readonly wall_ms: number;
16
+ readonly counter: number;
17
+ readonly node_id: string;
18
+ }
19
+
20
+ /**
21
+ * Create a new HLC timestamp initialized to zero for the given node.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const hlc = HLC.create('node-1');
26
+ * // hlc === { wall_ms: 0, counter: 0, node_id: 'node-1' }
27
+ * ```
28
+ */
29
+ const _create = (nodeId: string): HLCShape => ({
30
+ wall_ms: 0,
31
+ counter: 0,
32
+ node_id: nodeId,
33
+ });
34
+
35
+ /**
36
+ * Compare two HLC timestamps. Returns -1, 0, or 1.
37
+ *
38
+ * Compares wall_ms first, then counter, then node_id lexicographically.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const a = HLC.create('node-1');
43
+ * const b = HLC.increment(a, 1000);
44
+ * const cmp = HLC.compare(a, b);
45
+ * // cmp === -1 (a is before b)
46
+ * ```
47
+ */
48
+ export const compare = (a: HLCShape, b: HLCShape): -1 | 0 | 1 => {
49
+ if (a.wall_ms < b.wall_ms) return -1;
50
+ if (a.wall_ms > b.wall_ms) return 1;
51
+ if (a.counter < b.counter) return -1;
52
+ if (a.counter > b.counter) return 1;
53
+ if (a.node_id < b.node_id) return -1;
54
+ if (a.node_id > b.node_id) return 1;
55
+ return 0;
56
+ };
57
+
58
+ // 16-bit counter — supports 65535 events per ms before overflow
59
+ const MAX_COUNTER = 0xffff;
60
+
61
+ /**
62
+ * Increment an HLC for a local event.
63
+ *
64
+ * Advances wall_ms to max(current, now) and bumps the counter if the wall
65
+ * time didn't advance. Throws on counter overflow (`> 0xFFFF`).
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const hlc0 = HLC.create('node-1');
70
+ * const hlc1 = HLC.increment(hlc0, Date.now());
71
+ * // hlc1.wall_ms >= hlc0.wall_ms
72
+ * ```
73
+ */
74
+ const _increment = (hlc: HLCShape, now: number = 0): HLCShape => {
75
+ const newWallMs = Math.max(hlc.wall_ms, now);
76
+ if (newWallMs === hlc.wall_ms) {
77
+ const next = hlc.counter + 1;
78
+ if (next > MAX_COUNTER)
79
+ throw new Error(
80
+ `HLC counter overflow: exceeded ${MAX_COUNTER} (>65535 events in 1ms — consider batching or increasing clock resolution)`,
81
+ );
82
+ return { wall_ms: newWallMs, counter: next, node_id: hlc.node_id };
83
+ }
84
+ return { wall_ms: newWallMs, counter: 0, node_id: hlc.node_id };
85
+ };
86
+
87
+ /**
88
+ * Merge a local HLC with a remote HLC on message receive.
89
+ *
90
+ * Takes the max of local, remote, and now for wall_ms, then adjusts the
91
+ * counter accordingly. Preserves the local node_id.
92
+ *
93
+ * Lamport causality: if wall clocks agree, increment the higher counter to preserve
94
+ * happened-before ordering. Reset counter only when wall clock advances (new causal epoch).
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * const local = HLC.increment(HLC.create('A'), 1000);
99
+ * const remote = HLC.increment(HLC.create('B'), 2000);
100
+ * const merged = HLC.merge(local, remote, 1500);
101
+ * // merged.wall_ms === 2000, merged.node_id === 'A'
102
+ * ```
103
+ */
104
+ const _merge = (local: HLCShape, remote: HLCShape, now: number = 0): HLCShape => {
105
+ const newWallMs = Math.max(local.wall_ms, remote.wall_ms, now);
106
+ let newCounter: number;
107
+ if (newWallMs === local.wall_ms && newWallMs === remote.wall_ms) {
108
+ newCounter = Math.max(local.counter, remote.counter) + 1;
109
+ } else if (newWallMs === local.wall_ms) {
110
+ newCounter = local.counter + 1;
111
+ } else if (newWallMs === remote.wall_ms) {
112
+ newCounter = remote.counter + 1;
113
+ } else {
114
+ newCounter = 0;
115
+ }
116
+ if (newCounter > MAX_COUNTER)
117
+ throw new Error(
118
+ `HLC counter overflow: exceeded ${MAX_COUNTER} (>65535 events in 1ms — consider batching or increasing clock resolution)`,
119
+ );
120
+ return { wall_ms: newWallMs, counter: newCounter, node_id: local.node_id };
121
+ };
122
+
123
+ /**
124
+ * Encode an HLC timestamp to a colon-separated hex string.
125
+ *
126
+ * Format: `{wall_ms_hex_12}:{counter_hex_4}:{node_id}`
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * const hlc = HLC.increment(HLC.create('node-1'), 1000);
131
+ * const encoded = HLC.encode(hlc);
132
+ * // encoded === '0000000003e8:0000:node-1'
133
+ * ```
134
+ */
135
+ const _encode = (hlc: HLCShape): string => {
136
+ // 12 hex digits = 48-bit wall clock (good to year 10889), 4 hex = 16-bit counter
137
+ const wallHex = hlc.wall_ms.toString(16).padStart(12, '0');
138
+ const counterHex = hlc.counter.toString(16).padStart(4, '0');
139
+ return `${wallHex}:${counterHex}:${hlc.node_id}`;
140
+ };
141
+
142
+ /**
143
+ * Decode an HLC timestamp from a colon-separated hex string.
144
+ *
145
+ * Inverse of `encode`. Supports node IDs containing colons.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * const hlc = HLC.decode('0000000003e8:0000:node-1');
150
+ * // hlc === { wall_ms: 1000, counter: 0, node_id: 'node-1' }
151
+ * ```
152
+ */
153
+ const _decode = (s: string): HLCShape => {
154
+ const parts = s.split(':');
155
+ if (parts.length < 3) throw new Error(`Invalid HLC format: expected at least 3 colon-separated parts, got "${s}"`);
156
+ const wall_ms = parseInt(parts[0]!, 16);
157
+ const counter = parseInt(parts[1]!, 16);
158
+ const node_id = parts.slice(2).join(':');
159
+ if (isNaN(wall_ms)) throw new Error(`Invalid HLC format: wall_ms is not valid hex in "${s}"`);
160
+ if (isNaN(counter)) throw new Error(`Invalid HLC format: counter is not valid hex in "${s}"`);
161
+ return { wall_ms, counter, node_id };
162
+ };
163
+
164
+ /**
165
+ * Create a managed HLC clock as an Effect Ref.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * import { Effect } from 'effect';
170
+ *
171
+ * const program = Effect.gen(function* () {
172
+ * const clock = yield* HLC.makeClock('node-1');
173
+ * const ts = yield* HLC.tick(clock);
174
+ * // ts.wall_ms === Date.now() (approximately)
175
+ * });
176
+ * ```
177
+ */
178
+ export const makeClock = (nodeId: string): Effect.Effect<Ref.Ref<HLCShape>> => Ref.make(_create(nodeId));
179
+
180
+ /**
181
+ * Tick a managed clock forward, returning the new HLC timestamp.
182
+ *
183
+ * @example
184
+ * ```ts
185
+ * const ts = yield* HLC.tick(clock);
186
+ * // ts.wall_ms >= previous wall_ms
187
+ * ```
188
+ */
189
+ export const tick = (clock: Ref.Ref<HLCShape>): Effect.Effect<HLCShape> =>
190
+ Ref.updateAndGet(clock, (current) => _increment(current, Date.now()));
191
+
192
+ /**
193
+ * Receive a remote HLC timestamp and merge it into the managed clock.
194
+ *
195
+ * @example
196
+ * ```ts
197
+ * const remoteTs = HLC.decode(remoteEncoded);
198
+ * const merged = yield* HLC.receive(clock, remoteTs);
199
+ * // merged.wall_ms >= remoteTs.wall_ms
200
+ * ```
201
+ */
202
+ export const receive = (clock: Ref.Ref<HLCShape>, remote: HLCShape): Effect.Effect<HLCShape> =>
203
+ Ref.updateAndGet(clock, (current) => _merge(current, remote, Date.now()));
204
+
205
+ /**
206
+ * HLC namespace -- Hybrid Logical Clock.
207
+ *
208
+ * Pure functions for creating, comparing, incrementing, and merging HLC
209
+ * timestamps, plus Effect-based managed clock helpers. Encodes to/from
210
+ * a deterministic colon-separated hex string format.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * import { HLC } from '@czap/core';
215
+ *
216
+ * const a = HLC.increment(HLC.create('A'), Date.now());
217
+ * const b = HLC.increment(HLC.create('B'), Date.now());
218
+ * const merged = HLC.merge(a, b, Date.now());
219
+ * const encoded = HLC.encode(merged);
220
+ * const decoded = HLC.decode(encoded);
221
+ * ```
222
+ */
223
+ export const HLC = {
224
+ create: _create,
225
+ compare,
226
+ increment: _increment,
227
+ merge: _merge,
228
+ encode: _encode,
229
+ decode: _decode,
230
+ makeClock,
231
+ tick,
232
+ receive,
233
+ };
234
+
235
+ export declare namespace HLC {
236
+ /** Structural shape of a hybrid logical clock timestamp: `{ wall_ms, counter, node_id }`. */
237
+ export type Shape = HLCShape;
238
+ }