@plurnk/plurnk-service 1.3.12 → 1.4.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 (469) hide show
  1. package/.env.defaults +84 -77
  2. package/INSTALL.md +50 -25
  3. package/README.md +24 -10
  4. package/SPEC.md +2311 -928
  5. package/dist/Paths.d.ts +4 -1
  6. package/dist/Paths.d.ts.map +1 -1
  7. package/dist/Paths.js +23 -21
  8. package/dist/Paths.js.map +1 -1
  9. package/dist/build-info.json +1 -1
  10. package/dist/content/edit-receipt.d.ts +13 -28
  11. package/dist/content/edit-receipt.d.ts.map +1 -1
  12. package/dist/content/edit-receipt.js +285 -104
  13. package/dist/content/edit-receipt.js.map +1 -1
  14. package/dist/content/edited-span.d.ts.map +1 -1
  15. package/dist/content/edited-span.js +2 -5
  16. package/dist/content/edited-span.js.map +1 -1
  17. package/dist/content/index.d.ts +3 -3
  18. package/dist/content/index.d.ts.map +1 -1
  19. package/dist/content/index.js +1 -1
  20. package/dist/content/index.js.map +1 -1
  21. package/dist/content/line-marker.d.ts +6 -9
  22. package/dist/content/line-marker.d.ts.map +1 -1
  23. package/dist/content/line-marker.js +7 -11
  24. package/dist/content/line-marker.js.map +1 -1
  25. package/dist/content/matcher.d.ts +14 -25
  26. package/dist/content/matcher.d.ts.map +1 -1
  27. package/dist/content/matcher.js +77 -107
  28. package/dist/content/matcher.js.map +1 -1
  29. package/dist/content/mimetype-binary.d.ts +2 -2
  30. package/dist/content/mimetype-binary.d.ts.map +1 -1
  31. package/dist/content/mimetype-binary.js +10 -10
  32. package/dist/content/mimetype-binary.js.map +1 -1
  33. package/dist/content/path-mimetype.js +3 -3
  34. package/dist/content/path-mimetype.js.map +1 -1
  35. package/dist/content/read-resolve.d.ts +8 -4
  36. package/dist/content/read-resolve.d.ts.map +1 -1
  37. package/dist/content/read-resolve.js +101 -49
  38. package/dist/content/read-resolve.js.map +1 -1
  39. package/dist/core/BranchReceipt.d.ts +7 -0
  40. package/dist/core/BranchReceipt.d.ts.map +1 -0
  41. package/dist/core/BranchReceipt.js +27 -0
  42. package/dist/core/BranchReceipt.js.map +1 -0
  43. package/dist/core/BudgetOverflow.d.ts +23 -0
  44. package/dist/core/BudgetOverflow.d.ts.map +1 -0
  45. package/dist/core/BudgetOverflow.js +61 -0
  46. package/dist/core/BudgetOverflow.js.map +1 -0
  47. package/dist/core/BudgetReadout.d.ts +8 -0
  48. package/dist/core/BudgetReadout.d.ts.map +1 -0
  49. package/dist/core/BudgetReadout.js +79 -0
  50. package/dist/core/BudgetReadout.js.map +1 -0
  51. package/dist/core/ChannelWrite.d.ts +28 -9
  52. package/dist/core/ChannelWrite.d.ts.map +1 -1
  53. package/dist/core/ChannelWrite.js +28 -21
  54. package/dist/core/ChannelWrite.js.map +1 -1
  55. package/dist/core/ChannelWrite.sql +11 -10
  56. package/dist/core/CoreSchemeServices.d.ts +10 -4
  57. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  58. package/dist/core/CoreSchemeServices.js +7 -1
  59. package/dist/core/CoreSchemeServices.js.map +1 -1
  60. package/dist/core/Dispatcher.d.ts +29 -20
  61. package/dist/core/Dispatcher.d.ts.map +1 -1
  62. package/dist/core/Dispatcher.js +1488 -599
  63. package/dist/core/Dispatcher.js.map +1 -1
  64. package/dist/core/DurableStatement.d.ts +6 -0
  65. package/dist/core/DurableStatement.d.ts.map +1 -0
  66. package/dist/core/DurableStatement.js +51 -0
  67. package/dist/core/DurableStatement.js.map +1 -0
  68. package/dist/core/Engine.d.ts +48 -20
  69. package/dist/core/Engine.d.ts.map +1 -1
  70. package/dist/core/Engine.js +1208 -789
  71. package/dist/core/Engine.js.map +1 -1
  72. package/dist/core/Engine.sql +309 -217
  73. package/dist/core/EnvFlags.js +1 -1
  74. package/dist/core/EnvFlags.js.map +1 -1
  75. package/dist/core/ErrorDetail.d.ts +6 -0
  76. package/dist/core/ErrorDetail.d.ts.map +1 -0
  77. package/dist/core/ErrorDetail.js +20 -0
  78. package/dist/core/ErrorDetail.js.map +1 -0
  79. package/dist/core/ExecutorRegistry.d.ts +14 -3
  80. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  81. package/dist/core/ExecutorRegistry.js +56 -30
  82. package/dist/core/ExecutorRegistry.js.map +1 -1
  83. package/dist/core/GitBranch.d.ts +20 -0
  84. package/dist/core/GitBranch.d.ts.map +1 -0
  85. package/dist/core/GitBranch.js +110 -0
  86. package/dist/core/GitBranch.js.map +1 -0
  87. package/dist/core/JournalTurn.d.ts +9 -0
  88. package/dist/core/JournalTurn.d.ts.map +1 -0
  89. package/dist/core/JournalTurn.js +14 -0
  90. package/dist/core/JournalTurn.js.map +1 -0
  91. package/dist/core/JournalTurn.sql +10 -0
  92. package/dist/core/LogBody.d.ts +17 -0
  93. package/dist/core/LogBody.d.ts.map +1 -0
  94. package/dist/core/LogBody.js +148 -0
  95. package/dist/core/LogBody.js.map +1 -0
  96. package/dist/core/LoopFlagsReader.d.ts +7 -0
  97. package/dist/core/LoopFlagsReader.d.ts.map +1 -0
  98. package/dist/core/LoopFlagsReader.js +33 -0
  99. package/dist/core/LoopFlagsReader.js.map +1 -0
  100. package/dist/core/LoopLifecycle.d.ts +8 -1
  101. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  102. package/dist/core/LoopLifecycle.js +55 -9
  103. package/dist/core/LoopLifecycle.js.map +1 -1
  104. package/dist/core/LoopLifecycle.sql +9 -3
  105. package/dist/core/NoticeChannel.d.ts +13 -0
  106. package/dist/core/NoticeChannel.d.ts.map +1 -0
  107. package/dist/core/NoticeChannel.js +40 -0
  108. package/dist/core/NoticeChannel.js.map +1 -0
  109. package/dist/core/Owner.d.ts +0 -1
  110. package/dist/core/Owner.d.ts.map +1 -1
  111. package/dist/core/Owner.js +2 -5
  112. package/dist/core/Owner.js.map +1 -1
  113. package/dist/core/PacketBuilder.d.ts +25 -24
  114. package/dist/core/PacketBuilder.d.ts.map +1 -1
  115. package/dist/core/PacketBuilder.js +313 -375
  116. package/dist/core/PacketBuilder.js.map +1 -1
  117. package/dist/core/ProblemLog.d.ts +26 -0
  118. package/dist/core/ProblemLog.d.ts.map +1 -0
  119. package/dist/core/ProblemLog.js +58 -0
  120. package/dist/core/ProblemLog.js.map +1 -0
  121. package/dist/core/ProposalLifecycle.d.ts +15 -21
  122. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  123. package/dist/core/ProposalLifecycle.js +291 -78
  124. package/dist/core/ProposalLifecycle.js.map +1 -1
  125. package/dist/core/ProviderInstantiate.d.ts.map +1 -1
  126. package/dist/core/ProviderInstantiate.js +51 -48
  127. package/dist/core/ProviderInstantiate.js.map +1 -1
  128. package/dist/core/SchemeRegistry.d.ts +14 -8
  129. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  130. package/dist/core/SchemeRegistry.js +189 -114
  131. package/dist/core/SchemeRegistry.js.map +1 -1
  132. package/dist/core/ServiceTeardown.d.ts +11 -0
  133. package/dist/core/ServiceTeardown.d.ts.map +1 -0
  134. package/dist/core/ServiceTeardown.js +70 -0
  135. package/dist/core/ServiceTeardown.js.map +1 -0
  136. package/dist/core/StoredPacket.d.ts +29 -0
  137. package/dist/core/StoredPacket.d.ts.map +1 -0
  138. package/dist/core/StoredPacket.js +147 -0
  139. package/dist/core/StoredPacket.js.map +1 -0
  140. package/dist/core/StrikeRail.d.ts +1 -2
  141. package/dist/core/StrikeRail.d.ts.map +1 -1
  142. package/dist/core/StrikeRail.js +25 -55
  143. package/dist/core/StrikeRail.js.map +1 -1
  144. package/dist/core/WorkerControlAddress.d.ts +17 -0
  145. package/dist/core/WorkerControlAddress.d.ts.map +1 -0
  146. package/dist/core/WorkerControlAddress.js +44 -0
  147. package/dist/core/WorkerControlAddress.js.map +1 -0
  148. package/dist/core/WorkerName.d.ts +31 -0
  149. package/dist/core/WorkerName.d.ts.map +1 -0
  150. package/dist/core/WorkerName.js +95 -0
  151. package/dist/core/WorkerName.js.map +1 -0
  152. package/dist/core/WorkerName.sql +36 -0
  153. package/dist/core/WorkspaceGate.d.ts +14 -0
  154. package/dist/core/WorkspaceGate.d.ts.map +1 -0
  155. package/dist/core/WorkspaceGate.js +155 -0
  156. package/dist/core/WorkspaceGate.js.map +1 -0
  157. package/dist/core/caps/CapsResolve.d.ts +1 -1
  158. package/dist/core/caps/CapsResolve.d.ts.map +1 -1
  159. package/dist/core/caps/CapsResolve.js.map +1 -1
  160. package/dist/core/caps/DbChannelCaps.d.ts +5 -11
  161. package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
  162. package/dist/core/caps/DbChannelCaps.js +24 -8
  163. package/dist/core/caps/DbChannelCaps.js.map +1 -1
  164. package/dist/core/caps/DbEntryCaps.d.ts +4 -13
  165. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
  166. package/dist/core/caps/DbEntryCaps.js +15 -6
  167. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  168. package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
  169. package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
  170. package/dist/core/caps/DbNotifyCaps.js +12 -11
  171. package/dist/core/caps/DbNotifyCaps.js.map +1 -1
  172. package/dist/core/caps/DbProjectionCaps.d.ts +5 -5
  173. package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
  174. package/dist/core/caps/DbProjectionCaps.js +21 -4
  175. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  176. package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -4
  177. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
  178. package/dist/core/caps/DbSubscriptionCaps.js +57 -62
  179. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
  180. package/dist/core/caps/DbTagCaps.d.ts +5 -12
  181. package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
  182. package/dist/core/caps/DbTagCaps.js +14 -7
  183. package/dist/core/caps/DbTagCaps.js.map +1 -1
  184. package/dist/core/content-hash.js +1 -1
  185. package/dist/core/content-hash.js.map +1 -1
  186. package/dist/core/env-defaults.d.ts.map +1 -1
  187. package/dist/core/env-defaults.js.map +1 -1
  188. package/dist/core/fork.d.ts.map +1 -1
  189. package/dist/core/fork.js +55 -30
  190. package/dist/core/fork.js.map +1 -1
  191. package/dist/core/fork.sql +41 -27
  192. package/dist/core/git-env.d.ts +2 -0
  193. package/dist/core/git-env.d.ts.map +1 -1
  194. package/dist/core/git-env.js +13 -18
  195. package/dist/core/git-env.js.map +1 -1
  196. package/dist/core/git-iso.d.ts.map +1 -1
  197. package/dist/core/git-iso.js +9 -15
  198. package/dist/core/git-iso.js.map +1 -1
  199. package/dist/core/git-membership.d.ts +1 -1
  200. package/dist/core/git-membership.d.ts.map +1 -1
  201. package/dist/core/git-membership.js +198 -146
  202. package/dist/core/git-membership.js.map +1 -1
  203. package/dist/core/git-state.d.ts.map +1 -1
  204. package/dist/core/git-state.js +10 -11
  205. package/dist/core/git-state.js.map +1 -1
  206. package/dist/core/owner.sql +1 -1
  207. package/dist/core/packet-inject.d.ts.map +1 -1
  208. package/dist/core/packet-inject.js +7 -11
  209. package/dist/core/packet-inject.js.map +1 -1
  210. package/dist/core/packet-wire.d.ts +2 -20
  211. package/dist/core/packet-wire.d.ts.map +1 -1
  212. package/dist/core/packet-wire.js +242 -368
  213. package/dist/core/packet-wire.js.map +1 -1
  214. package/dist/core/plurnk-uri.d.ts +12 -1
  215. package/dist/core/plurnk-uri.d.ts.map +1 -1
  216. package/dist/core/plurnk-uri.js +49 -29
  217. package/dist/core/plurnk-uri.js.map +1 -1
  218. package/dist/core/results.d.ts +16 -5
  219. package/dist/core/results.d.ts.map +1 -1
  220. package/dist/core/results.js +27 -18
  221. package/dist/core/results.js.map +1 -1
  222. package/dist/core/ruler_count.d.ts +4 -0
  223. package/dist/core/ruler_count.d.ts.map +1 -0
  224. package/dist/core/ruler_count.js +7 -0
  225. package/dist/core/ruler_count.js.map +1 -0
  226. package/dist/core/scheme-types.d.ts +9 -11
  227. package/dist/core/scheme-types.d.ts.map +1 -1
  228. package/dist/core/scheme-types.js.map +1 -1
  229. package/dist/core/search-gate.d.ts.map +1 -1
  230. package/dist/core/search-gate.js +3 -11
  231. package/dist/core/search-gate.js.map +1 -1
  232. package/dist/core/teaching-corpus.d.ts +6 -0
  233. package/dist/core/teaching-corpus.d.ts.map +1 -0
  234. package/dist/core/teaching-corpus.js +23 -0
  235. package/dist/core/teaching-corpus.js.map +1 -0
  236. package/dist/core/teaching.d.ts +0 -1
  237. package/dist/core/teaching.d.ts.map +1 -1
  238. package/dist/core/teaching.js +2 -8
  239. package/dist/core/teaching.js.map +1 -1
  240. package/dist/core/token-ruler.d.ts.map +1 -1
  241. package/dist/core/token-ruler.js +3 -16
  242. package/dist/core/token-ruler.js.map +1 -1
  243. package/dist/core/turn-scheduler.d.ts +1 -1
  244. package/dist/core/turn-scheduler.d.ts.map +1 -1
  245. package/dist/core/turn-scheduler.js +1 -1
  246. package/dist/core/turn-scheduler.js.map +1 -1
  247. package/dist/core/worker-cap.d.ts +2 -4
  248. package/dist/core/worker-cap.d.ts.map +1 -1
  249. package/dist/core/worker-cap.js +13 -4
  250. package/dist/core/worker-cap.js.map +1 -1
  251. package/dist/core/{run-ops.sql → worker-ops.sql} +11 -11
  252. package/dist/core/workspace-settings.d.ts.map +1 -1
  253. package/dist/core/workspace-settings.js +17 -9
  254. package/dist/core/workspace-settings.js.map +1 -1
  255. package/dist/digest/Digest.d.ts +2 -1
  256. package/dist/digest/Digest.d.ts.map +1 -1
  257. package/dist/digest/Digest.js +337 -138
  258. package/dist/digest/Digest.js.map +1 -1
  259. package/dist/digest/digest.sql +19 -10
  260. package/dist/index.d.ts.map +1 -1
  261. package/dist/index.js +3 -5
  262. package/dist/index.js.map +1 -1
  263. package/dist/matrix/live-specimen.d.ts +9 -0
  264. package/dist/matrix/live-specimen.d.ts.map +1 -0
  265. package/dist/matrix/live-specimen.js +37 -0
  266. package/dist/matrix/live-specimen.js.map +1 -0
  267. package/dist/observe/api.d.ts +6 -0
  268. package/dist/observe/api.d.ts.map +1 -0
  269. package/dist/observe/api.js +11 -0
  270. package/dist/observe/api.js.map +1 -0
  271. package/dist/observe/init.d.ts +7 -0
  272. package/dist/observe/init.d.ts.map +1 -0
  273. package/dist/observe/init.js +159 -0
  274. package/dist/observe/init.js.map +1 -0
  275. package/dist/observe/metrics.d.ts +6 -0
  276. package/dist/observe/metrics.d.ts.map +1 -0
  277. package/dist/observe/metrics.js +15 -0
  278. package/dist/observe/metrics.js.map +1 -0
  279. package/dist/observe/spans.d.ts +4 -0
  280. package/dist/observe/spans.d.ts.map +1 -0
  281. package/dist/observe/spans.js +51 -0
  282. package/dist/observe/spans.js.map +1 -0
  283. package/dist/schemes/EffectPolicy.d.ts +1 -0
  284. package/dist/schemes/EffectPolicy.d.ts.map +1 -1
  285. package/dist/schemes/EffectPolicy.js +5 -2
  286. package/dist/schemes/EffectPolicy.js.map +1 -1
  287. package/dist/schemes/Exec.d.ts +6 -11
  288. package/dist/schemes/Exec.d.ts.map +1 -1
  289. package/dist/schemes/Exec.js +364 -247
  290. package/dist/schemes/Exec.js.map +1 -1
  291. package/dist/schemes/ExecOutputScheme.d.ts +8 -7
  292. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  293. package/dist/schemes/ExecOutputScheme.js +48 -9
  294. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  295. package/dist/schemes/File.d.ts +7 -11
  296. package/dist/schemes/File.d.ts.map +1 -1
  297. package/dist/schemes/File.js +279 -142
  298. package/dist/schemes/File.js.map +1 -1
  299. package/dist/schemes/Log.d.ts +4 -8
  300. package/dist/schemes/Log.d.ts.map +1 -1
  301. package/dist/schemes/Log.js +475 -208
  302. package/dist/schemes/Log.js.map +1 -1
  303. package/dist/schemes/Log.sql +62 -30
  304. package/dist/schemes/Prompt.d.ts +3 -2
  305. package/dist/schemes/Prompt.d.ts.map +1 -1
  306. package/dist/schemes/Prompt.js +9 -6
  307. package/dist/schemes/Prompt.js.map +1 -1
  308. package/dist/schemes/Skill.d.ts +1 -1
  309. package/dist/schemes/Skill.d.ts.map +1 -1
  310. package/dist/schemes/Skill.js +2 -3
  311. package/dist/schemes/Skill.js.map +1 -1
  312. package/dist/schemes/Worker.d.ts +8 -16
  313. package/dist/schemes/Worker.d.ts.map +1 -1
  314. package/dist/schemes/Worker.js +179 -69
  315. package/dist/schemes/Worker.js.map +1 -1
  316. package/dist/schemes/_entry-chunk.d.ts.map +1 -1
  317. package/dist/schemes/_entry-chunk.js +12 -5
  318. package/dist/schemes/_entry-chunk.js.map +1 -1
  319. package/dist/schemes/_entry-crud.d.ts +10 -9
  320. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  321. package/dist/schemes/_entry-crud.js +59 -13
  322. package/dist/schemes/_entry-crud.js.map +1 -1
  323. package/dist/schemes/_entry-crud.sql +20 -8
  324. package/dist/schemes/_entry-find.d.ts +20 -15
  325. package/dist/schemes/_entry-find.d.ts.map +1 -1
  326. package/dist/schemes/_entry-find.js +339 -174
  327. package/dist/schemes/_entry-find.js.map +1 -1
  328. package/dist/schemes/_entry-find.sql +20 -8
  329. package/dist/schemes/_entry-graph.d.ts +4 -2
  330. package/dist/schemes/_entry-graph.d.ts.map +1 -1
  331. package/dist/schemes/_entry-graph.js +55 -31
  332. package/dist/schemes/_entry-graph.js.map +1 -1
  333. package/dist/schemes/_entry-graph.sql +37 -22
  334. package/dist/schemes/_entry-manifest.d.ts +10 -15
  335. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  336. package/dist/schemes/_entry-manifest.js +50 -268
  337. package/dist/schemes/_entry-manifest.js.map +1 -1
  338. package/dist/schemes/_entry-ops.d.ts +9 -14
  339. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  340. package/dist/schemes/_entry-ops.js +149 -77
  341. package/dist/schemes/_entry-ops.js.map +1 -1
  342. package/dist/schemes/_entry-ops.sql +1 -1
  343. package/dist/schemes/_entry-semantic.d.ts +23 -8
  344. package/dist/schemes/_entry-semantic.d.ts.map +1 -1
  345. package/dist/schemes/_entry-semantic.js +141 -60
  346. package/dist/schemes/_entry-semantic.js.map +1 -1
  347. package/dist/schemes/_entry-semantic.sql +63 -45
  348. package/dist/schemes/_entry-send.d.ts +3 -4
  349. package/dist/schemes/_entry-send.d.ts.map +1 -1
  350. package/dist/schemes/_entry-send.js +48 -23
  351. package/dist/schemes/_entry-send.js.map +1 -1
  352. package/dist/schemes/_path-scope.d.ts +23 -0
  353. package/dist/schemes/_path-scope.d.ts.map +1 -0
  354. package/dist/schemes/_path-scope.js +61 -0
  355. package/dist/schemes/_path-scope.js.map +1 -0
  356. package/dist/schemes/_search-candidate.d.ts +20 -0
  357. package/dist/schemes/_search-candidate.d.ts.map +1 -0
  358. package/dist/schemes/_search-candidate.js +19 -0
  359. package/dist/schemes/_search-candidate.js.map +1 -0
  360. package/dist/schemes/_search-exclusion.d.ts +7 -0
  361. package/dist/schemes/_search-exclusion.d.ts.map +1 -0
  362. package/dist/schemes/_search-exclusion.js +23 -0
  363. package/dist/schemes/_search-exclusion.js.map +1 -0
  364. package/dist/schemes/_search-index.d.ts +6 -0
  365. package/dist/schemes/_search-index.d.ts.map +1 -0
  366. package/dist/schemes/_search-index.js +326 -0
  367. package/dist/schemes/_search-index.js.map +1 -0
  368. package/dist/schemes/cosine.js +1 -1
  369. package/dist/schemes/cosine.js.map +1 -1
  370. package/dist/schemes/exec-abort.js +3 -3
  371. package/dist/schemes/exec-abort.js.map +1 -1
  372. package/dist/schemes/exec-env.js +3 -3
  373. package/dist/schemes/exec-env.js.map +1 -1
  374. package/dist/server/BranchBatches.d.ts +48 -0
  375. package/dist/server/BranchBatches.d.ts.map +1 -0
  376. package/dist/server/BranchBatches.js +591 -0
  377. package/dist/server/BranchBatches.js.map +1 -0
  378. package/dist/server/Daemon.d.ts +36 -66
  379. package/dist/server/Daemon.d.ts.map +1 -1
  380. package/dist/server/Daemon.js +920 -446
  381. package/dist/server/Daemon.js.map +1 -1
  382. package/dist/server/DaemonModule.d.ts +31 -0
  383. package/dist/server/DaemonModule.d.ts.map +1 -0
  384. package/dist/server/DaemonModule.js +2 -0
  385. package/dist/server/DaemonModule.js.map +1 -0
  386. package/dist/server/branch-batch.sql +152 -0
  387. package/dist/server/client-input.d.ts +12 -0
  388. package/dist/server/client-input.d.ts.map +1 -1
  389. package/dist/server/client-input.js +262 -57
  390. package/dist/server/client-input.js.map +1 -1
  391. package/dist/server/dispatch-as-plurnk.d.ts +1 -1
  392. package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
  393. package/dist/server/dispatch-as-plurnk.js +15 -7
  394. package/dist/server/dispatch-as-plurnk.js.map +1 -1
  395. package/dist/server/drain.sql +92 -62
  396. package/dist/server/envelope.d.ts +2 -5
  397. package/dist/server/envelope.d.ts.map +1 -1
  398. package/dist/server/envelope.js +119 -95
  399. package/dist/server/envelope.js.map +1 -1
  400. package/dist/server/envelope.sql +19 -23
  401. package/dist/server/exec-poll-backoff.js +1 -1
  402. package/dist/server/exec-poll-backoff.js.map +1 -1
  403. package/dist/server/lifecycle-recovery.sql +79 -2
  404. package/dist/server/logEntry.d.ts +3 -1
  405. package/dist/server/logEntry.d.ts.map +1 -1
  406. package/dist/server/logEntry.js +4 -2
  407. package/dist/server/logEntry.js.map +1 -1
  408. package/dist/server/logEntry.sql +1 -1
  409. package/dist/server/loop-model.d.ts.map +1 -1
  410. package/dist/server/loop-model.js +22 -9
  411. package/dist/server/loop-model.js.map +1 -1
  412. package/dist/server/loopDocs.d.ts.map +1 -1
  413. package/dist/server/loopDocs.js +5 -4
  414. package/dist/server/loopDocs.js.map +1 -1
  415. package/dist/server/seam-entry-read.sql +15 -10
  416. package/dist/server/seam-log-read.sql +2 -2
  417. package/dist/server/seam-loop.sql +1 -1
  418. package/dist/server/seam-proposal-list.sql +17 -7
  419. package/dist/service.d.ts.map +1 -1
  420. package/dist/service.js +66 -60
  421. package/dist/service.js.map +1 -1
  422. package/migrations/001_schema.sql +897 -0
  423. package/package.json +57 -26
  424. package/dist/core/PluginLoader.d.ts +0 -20
  425. package/dist/core/PluginLoader.d.ts.map +0 -1
  426. package/dist/core/PluginLoader.js +0 -142
  427. package/dist/core/PluginLoader.js.map +0 -1
  428. package/dist/core/TelemetryChannel.d.ts +0 -37
  429. package/dist/core/TelemetryChannel.d.ts.map +0 -1
  430. package/dist/core/TelemetryChannel.js +0 -80
  431. package/dist/core/TelemetryChannel.js.map +0 -1
  432. package/dist/core/path-decode.d.ts +0 -3
  433. package/dist/core/path-decode.d.ts.map +0 -1
  434. package/dist/core/path-decode.js +0 -9
  435. package/dist/core/path-decode.js.map +0 -1
  436. package/dist/core/plugin-attribution.d.ts +0 -5
  437. package/dist/core/plugin-attribution.d.ts.map +0 -1
  438. package/dist/core/plugin-attribution.js +0 -39
  439. package/dist/core/plugin-attribution.js.map +0 -1
  440. package/dist/core/world-state.d.ts +0 -10
  441. package/dist/core/world-state.d.ts.map +0 -1
  442. package/dist/core/world-state.js +0 -35
  443. package/dist/core/world-state.js.map +0 -1
  444. package/dist/core/world-state.sql +0 -35
  445. package/dist/core/zero-pin.d.ts +0 -3
  446. package/dist/core/zero-pin.d.ts.map +0 -1
  447. package/dist/core/zero-pin.js +0 -16
  448. package/dist/core/zero-pin.js.map +0 -1
  449. package/dist/server/auto.d.ts +0 -6
  450. package/dist/server/auto.d.ts.map +0 -1
  451. package/dist/server/auto.js +0 -63
  452. package/dist/server/auto.js.map +0 -1
  453. package/dist/server/clientTurn.d.ts +0 -6
  454. package/dist/server/clientTurn.d.ts.map +0 -1
  455. package/dist/server/clientTurn.js +0 -22
  456. package/dist/server/clientTurn.js.map +0 -1
  457. package/dist/server/clientTurn.sql +0 -10
  458. package/dist/server/noProposals.d.ts +0 -6
  459. package/dist/server/noProposals.d.ts.map +0 -1
  460. package/dist/server/noProposals.js +0 -37
  461. package/dist/server/noProposals.js.map +0 -1
  462. package/dist/server/version-info.d.ts +0 -14
  463. package/dist/server/version-info.d.ts.map +0 -1
  464. package/dist/server/version-info.js +0 -69
  465. package/dist/server/version-info.js.map +0 -1
  466. package/migrations/0000-00-00.01_schema.sql +0 -536
  467. package/migrations/0004_loop-provider.sql +0 -3
  468. package/migrations/0005_subscription-published-channel.sql +0 -3
  469. package/migrations/0006_loop-max-turns.sql +0 -3
@@ -0,0 +1,897 @@
1
+ -- MIGRATE: 1 baseline
2
+ -- The single current pre-release schema baseline. Shape changes replace it;
3
+ -- existing development databases are deleted and recreated, never upgraded.
4
+
5
+ -- workspaces
6
+ -- project_root: workspace pointer. NULL = headless (no disk side-effects);
7
+ -- non-null = absolute path to the client's source tree, supplied at
8
+ -- workspace.create or workspace.set_root.
9
+ CREATE TABLE IF NOT EXISTS workspaces (
10
+ id INTEGER NOT NULL PRIMARY KEY,
11
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
12
+ name TEXT NOT NULL UNIQUE CHECK (length(name) > 0),
13
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
14
+ cost_usd REAL DEFAULT 0 CHECK (cost_usd IS NULL OR cost_usd >= 0),
15
+ project_root TEXT,
16
+ -- {§operator-config} validated client workspace settings; each field composes
17
+ -- with operator configuration at its owning use site.
18
+ settings TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(settings))
19
+ ) STRICT;
20
+
21
+ CREATE INDEX IF NOT EXISTS workspaces_created_at ON workspaces (created_at);
22
+
23
+ -- workers
24
+ CREATE TABLE IF NOT EXISTS workers (
25
+ id INTEGER NOT NULL PRIMARY KEY,
26
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
27
+ workspace_id INTEGER NOT NULL,
28
+ name TEXT NOT NULL CHECK (length(name) > 0),
29
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
30
+ -- workers fork via parent_worker_id; workspaces carry no parent — {§machine-processes-no-fork-workspace}
31
+ parent_worker_id INTEGER CHECK (parent_worker_id IS NULL OR parent_worker_id != id),
32
+ cost_usd REAL DEFAULT 0 CHECK (cost_usd IS NULL OR cost_usd >= 0),
33
+ origin TEXT NOT NULL DEFAULT 'client' CHECK (origin IN ('model', 'client', 'plurnk')),
34
+ -- {§methods-model-worker}: durable identity for the workspace's stable
35
+ -- default conversation; unrelated to its human-facing, reclaimable name.
36
+ default_conversation INTEGER NOT NULL DEFAULT 0 CHECK (default_conversation IN (0, 1)),
37
+ -- {§env-delta-log-pull}: monotonic observation progress, not a private world snapshot.
38
+ -- NULL means the worker has not established its first-turn baseline yet.
39
+ ambient_event_cursor INTEGER CHECK (ambient_event_cursor IS NULL OR ambient_event_cursor >= 0),
40
+ CHECK (default_conversation = 0 OR (origin = 'model' AND parent_worker_id IS NULL)),
41
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE,
42
+ FOREIGN KEY (parent_worker_id) REFERENCES workers(id) ON DELETE CASCADE
43
+ ) STRICT;
44
+
45
+ CREATE INDEX IF NOT EXISTS workers_workspace_id_created_at ON workers (workspace_id, created_at);
46
+ CREATE INDEX IF NOT EXISTS workers_parent_worker_id ON workers (parent_worker_id);
47
+ CREATE UNIQUE INDEX IF NOT EXISTS workers_workspace_default_conversation
48
+ ON workers (workspace_id) WHERE default_conversation = 1;
49
+ -- NOT unique: a name is frozen per worker ({§machine-processes-worker-origin}) but RECLAIMABLE across
50
+ -- time — a terminated worker keeps its name in permanent history while a fresh spawn reuses it;
51
+ -- worker_resolve_by_name picks the newest. A LIVE collision is refused at the spawn gate (Worker.edit
52
+ -- → worker_live_by_name → 409), never by this index. Indexed for the by-name resolve/spawn lookup.
53
+ CREATE INDEX IF NOT EXISTS workers_workspace_name ON workers (workspace_id, name);
54
+
55
+ -- {§env-delta-log-pull}: one append-only occurrence journal gives every ambient
56
+ -- producer a shared monotonic order. It snapshots only what the observer row
57
+ -- needs; shared-world contents remain owned by entries/files, never copied here.
58
+ -- source_record_id is forensic identity for the originating log/loop row, not a
59
+ -- foreign key: model log curation must not erase an already-recorded occurrence.
60
+ CREATE TABLE IF NOT EXISTS ambient_events (
61
+ id INTEGER NOT NULL PRIMARY KEY,
62
+ workspace_id INTEGER NOT NULL,
63
+ producer_worker_id INTEGER NOT NULL,
64
+ kind TEXT NOT NULL CHECK (kind IN ('edit', 'loop_termination')),
65
+ source_record_id INTEGER NOT NULL CHECK (source_record_id >= 1),
66
+ source TEXT,
67
+ op TEXT NOT NULL CHECK (op IN ('EDIT', 'SEND')),
68
+ scheme TEXT,
69
+ hostname TEXT,
70
+ pathname TEXT,
71
+ rx TEXT,
72
+ attrs TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attrs)),
73
+ status_rx INTEGER NOT NULL CHECK (status_rx BETWEEN 100 AND 599),
74
+ prompt TEXT,
75
+ terminated_by TEXT CHECK (terminated_by IS NULL OR terminated_by = 'cancel'),
76
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
77
+ CHECK (
78
+ (kind = 'edit' AND op = 'EDIT' AND rx IS NOT NULL AND prompt IS NULL AND terminated_by IS NULL)
79
+ OR
80
+ (kind = 'loop_termination' AND op = 'SEND' AND scheme = 'worker' AND prompt IS NOT NULL)
81
+ ),
82
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE,
83
+ FOREIGN KEY (producer_worker_id) REFERENCES workers(id) ON DELETE CASCADE
84
+ ) STRICT;
85
+
86
+ CREATE INDEX IF NOT EXISTS ambient_events_workspace_id_id
87
+ ON ambient_events (workspace_id, id);
88
+ CREATE INDEX IF NOT EXISTS ambient_events_producer_kind_id
89
+ ON ambient_events (producer_worker_id, kind, id);
90
+
91
+ -- loops
92
+ -- flags: per-loop runtime flags (auto, noProposals, noWeb, noInteraction,
93
+ -- mode). JSON column, merged over DEFAULT_LOOP_FLAGS in code so missing
94
+ -- keys read as their defaults. SchemeRegistry.resolveForLoop gates schemes
95
+ -- by manifest affinity (excludedInAsk / requiresWeb / requiresInteraction).
96
+ CREATE TABLE IF NOT EXISTS loops (
97
+ id INTEGER NOT NULL PRIMARY KEY,
98
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
99
+ worker_id INTEGER NOT NULL,
100
+ sequence INTEGER NOT NULL CHECK (sequence >= 1),
101
+ status INTEGER NOT NULL DEFAULT 102 CHECK (status IN (100, 102, 200, 202, 413, 429, 499, 500, 504, 508)),
102
+ prompt TEXT NOT NULL,
103
+ flags TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(flags)),
104
+ provider_spec TEXT NOT NULL DEFAULT 'null' CHECK (json_valid(provider_spec)),
105
+ max_turns INTEGER NOT NULL DEFAULT 50 CHECK (max_turns >= -1),
106
+ -- {§methods-loop-run-open-paths}: the initial prompt frame's selected paths,
107
+ -- held here until turn 1 materializes that frame (string[] JSON).
108
+ open_paths TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(open_paths)),
109
+ -- {§prompt-loop-containment}: one queued recovery loop may carry the
110
+ -- complete orphan frame set of one concluded source loop.
111
+ orphan_source_loop_id INTEGER,
112
+ -- {§worker-scheme} loop-termination delta: terminated_at is stamped by the trigger
113
+ -- below when status crosses into terminal (every death-path, uniformly);
114
+ -- terminal_message is the deliverable — the SEND[200] body or the abandonment
115
+ -- reason — set by the guarded terminal lifecycle transition.
116
+ terminated_at TEXT,
117
+ terminal_message TEXT,
118
+ terminal_result TEXT CHECK (terminal_result IS NULL OR json_valid(terminal_result)),
119
+ -- {§loop-terminal-authorship}: 'cancel' names an external loop.cancel;
120
+ -- NULL covers model terminals and engine verdicts whose result carries the story.
121
+ terminated_by TEXT CHECK (terminated_by IS NULL OR terminated_by = 'cancel'),
122
+ FOREIGN KEY (worker_id) REFERENCES workers(id) ON DELETE CASCADE,
123
+ FOREIGN KEY (orphan_source_loop_id) REFERENCES loops(id)
124
+ ) STRICT;
125
+
126
+ CREATE UNIQUE INDEX IF NOT EXISTS loops_worker_id_sequence ON loops (worker_id, sequence);
127
+ CREATE UNIQUE INDEX IF NOT EXISTS loops_orphan_source_loop_id ON loops (orphan_source_loop_id);
128
+
129
+ -- {§worker-scheme}: a loop crossing into a terminal status stamps terminated_at, so sibling
130
+ -- workers pull the termination as a folded ambient delta — caught uniformly across every
131
+ -- death-path (SEND, grinder, max-turns, strike, KILL). The stamp updates terminated_at,
132
+ -- never status, so it cannot re-fire this trigger. Terminals: 200 done · 413 budget ·
133
+ -- 429 turn-ceiling · 499 cancel · 500 fail · 504 wall-clock timeout · 508 runaway. (202 = parked/sleeping, NOT terminal.)
134
+ CREATE TRIGGER IF NOT EXISTS loops_stamp_terminated_at
135
+ AFTER UPDATE OF status ON loops
136
+ WHEN NEW.status IN (200, 413, 429, 499, 500, 504, 508) AND OLD.status NOT IN (200, 413, 429, 499, 500, 504, 508)
137
+ BEGIN
138
+ UPDATE loops SET terminated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = NEW.id;
139
+ END;
140
+
141
+ -- A terminal transition is an ambient occurrence in the same total order as a
142
+ -- shared EDIT. Directly inserted fork history never crosses this transition and
143
+ -- therefore cannot fabricate a new conclusion event.
144
+ CREATE TRIGGER IF NOT EXISTS loops_append_ambient_event
145
+ AFTER UPDATE OF status ON loops
146
+ WHEN NEW.status IN (200, 413, 429, 499, 500, 504, 508) AND OLD.status NOT IN (200, 413, 429, 499, 500, 504, 508)
147
+ BEGIN
148
+ INSERT INTO ambient_events (
149
+ workspace_id, producer_worker_id, kind, source_record_id, source,
150
+ op, scheme, pathname, rx, status_rx, prompt, terminated_by
151
+ )
152
+ SELECT w.workspace_id, NEW.worker_id, 'loop_termination', NEW.id, NULL,
153
+ 'SEND', 'worker', '/' || w.name, NEW.terminal_message, NEW.status, NEW.prompt, NEW.terminated_by
154
+ FROM workers w
155
+ WHERE w.id = NEW.worker_id;
156
+ END;
157
+
158
+ CREATE TRIGGER IF NOT EXISTS loops_result_contract_insert
159
+ BEFORE INSERT ON loops
160
+ WHEN NEW.status IN (100, 102, 200, 202, 413, 429, 499, 500, 504, 508)
161
+ AND NOT (
162
+ (NEW.status IN (100, 102, 202) AND NEW.terminal_result IS NULL)
163
+ OR (
164
+ NEW.status IN (200, 413, 429, 499, 500, 504, 508)
165
+ AND NEW.terminal_result IS NOT NULL
166
+ AND json_valid(NEW.terminal_result)
167
+ AND json_type(NEW.terminal_result, '$.status') = 'integer'
168
+ AND (
169
+ json_extract(NEW.terminal_result, '$.status') = NEW.status
170
+ OR (
171
+ NEW.status = 200
172
+ AND json_extract(NEW.terminal_result, '$.status') BETWEEN 200 AND 399
173
+ AND json_extract(NEW.terminal_result, '$.status') != 202
174
+ )
175
+ OR (
176
+ NEW.status = 500
177
+ AND json_extract(NEW.terminal_result, '$.status') BETWEEN 400 AND 599
178
+ )
179
+ )
180
+ AND (
181
+ (NEW.status < 400 AND json_type(NEW.terminal_result, '$.problem') IS NULL)
182
+ OR (
183
+ NEW.status >= 400
184
+ AND json_type(NEW.terminal_result, '$.problem') = 'object'
185
+ AND json_extract(NEW.terminal_result, '$.problem.status')
186
+ = json_extract(NEW.terminal_result, '$.status')
187
+ AND length(json_extract(NEW.terminal_result, '$.problem.type')) > 0
188
+ AND length(json_extract(NEW.terminal_result, '$.problem.title')) > 0
189
+ AND length(json_extract(NEW.terminal_result, '$.problem.detail')) > 0
190
+ AND length(json_extract(NEW.terminal_result, '$.problem.instance')) > 0
191
+ )
192
+ )
193
+ )
194
+ )
195
+ BEGIN
196
+ SELECT RAISE(ABORT, 'loop terminal result violates the operation-result contract');
197
+ END;
198
+
199
+ CREATE TRIGGER IF NOT EXISTS loops_result_contract_update
200
+ BEFORE UPDATE OF status, terminal_result ON loops
201
+ WHEN NEW.status IN (100, 102, 200, 202, 413, 429, 499, 500, 504, 508)
202
+ AND NOT (
203
+ (NEW.status IN (100, 102, 202) AND NEW.terminal_result IS NULL)
204
+ OR (
205
+ NEW.status IN (200, 413, 429, 499, 500, 504, 508)
206
+ AND NEW.terminal_result IS NOT NULL
207
+ AND json_valid(NEW.terminal_result)
208
+ AND json_type(NEW.terminal_result, '$.status') = 'integer'
209
+ AND (
210
+ json_extract(NEW.terminal_result, '$.status') = NEW.status
211
+ OR (
212
+ NEW.status = 200
213
+ AND json_extract(NEW.terminal_result, '$.status') BETWEEN 200 AND 399
214
+ AND json_extract(NEW.terminal_result, '$.status') != 202
215
+ )
216
+ OR (
217
+ NEW.status = 500
218
+ AND json_extract(NEW.terminal_result, '$.status') BETWEEN 400 AND 599
219
+ )
220
+ )
221
+ AND (
222
+ (NEW.status < 400 AND json_type(NEW.terminal_result, '$.problem') IS NULL)
223
+ OR (
224
+ NEW.status >= 400
225
+ AND json_type(NEW.terminal_result, '$.problem') = 'object'
226
+ AND json_extract(NEW.terminal_result, '$.problem.status')
227
+ = json_extract(NEW.terminal_result, '$.status')
228
+ AND length(json_extract(NEW.terminal_result, '$.problem.type')) > 0
229
+ AND length(json_extract(NEW.terminal_result, '$.problem.title')) > 0
230
+ AND length(json_extract(NEW.terminal_result, '$.problem.detail')) > 0
231
+ AND length(json_extract(NEW.terminal_result, '$.problem.instance')) > 0
232
+ )
233
+ )
234
+ )
235
+ )
236
+ BEGIN
237
+ SELECT RAISE(ABORT, 'loop terminal result violates the operation-result contract');
238
+ END;
239
+
240
+ -- turns
241
+ -- finish_reason / model: provider-call metadata from the provider response contract.
242
+ -- Properties of the call, not of the model's emission payload — kept on
243
+ -- the Turn row alongside usage rather than nested into packet.assistant.
244
+ CREATE TABLE IF NOT EXISTS turns (
245
+ id INTEGER NOT NULL PRIMARY KEY,
246
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
247
+ loop_id INTEGER NOT NULL,
248
+ sequence INTEGER NOT NULL CHECK (sequence >= 1),
249
+ timestamp TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
250
+ status INTEGER NOT NULL CHECK (status BETWEEN 100 AND 599),
251
+ usage_prompt INTEGER NOT NULL DEFAULT 0 CHECK (usage_prompt >= 0),
252
+ usage_completion INTEGER NOT NULL DEFAULT 0 CHECK (usage_completion >= 0),
253
+ usage_reasoning INTEGER NOT NULL DEFAULT 0 CHECK (usage_reasoning >= 0),
254
+ usage_cached INTEGER NOT NULL DEFAULT 0 CHECK (usage_cached >= 0),
255
+ usage_cost TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(usage_cost) AND json_type(usage_cost) = 'array'),
256
+ usage_cost_usd REAL DEFAULT 0 CHECK (usage_cost_usd IS NULL OR usage_cost_usd >= 0),
257
+ -- Effective packet allowance for this turn's provider and policy; NULL is
258
+ -- uncapped or unknown. {§tokenomics-client-gauge}
259
+ usage_prompt_budget INTEGER CHECK (usage_prompt_budget IS NULL OR usage_prompt_budget >= 1),
260
+ -- {§packet-stored-shape}: NULL means no model request was assembled. A
261
+ -- present packet is either the measured request or that request extended
262
+ -- by the paired admitted-response fields.
263
+ packet TEXT CHECK (
264
+ CASE
265
+ WHEN packet IS NULL THEN 1
266
+ WHEN json_valid(packet) = 0 THEN 0
267
+ ELSE COALESCE(
268
+ json_type(packet) = 'object'
269
+ AND json_type(packet, '$.tokens') = 'integer'
270
+ AND json_extract(packet, '$.tokens') >= 0
271
+ AND json_type(packet, '$.sections') = 'array'
272
+ AND json_type(packet, '$.attributions') = 'array'
273
+ AND (
274
+ (
275
+ json_type(packet, '$.assistant') IS NULL
276
+ AND json_type(packet, '$.assistantRaw') IS NULL
277
+ )
278
+ OR (
279
+ json_type(packet, '$.assistant') = 'object'
280
+ AND json_type(packet, '$.assistant.content') = 'text'
281
+ AND json_type(packet, '$.assistant.ops') = 'array'
282
+ AND json_type(packet, '$.assistant.reasoning') IN ('text', 'null')
283
+ AND json_type(packet, '$.assistantRaw') IS NOT NULL
284
+ )
285
+ ),
286
+ 0
287
+ )
288
+ END
289
+ ),
290
+ finish_reason TEXT,
291
+ model TEXT NOT NULL DEFAULT 'unknown' CHECK (length(model) >= 1),
292
+ -- Opaque provider→client metadata plus engine rail keys; JSON-valid but
293
+ -- otherwise unenforced. {§meta-passthrough}, {§rail-truth-engine-verdict}
294
+ meta TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(meta)),
295
+ FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE
296
+ ) STRICT;
297
+
298
+ CREATE UNIQUE INDEX IF NOT EXISTS turns_loop_id_sequence ON turns (loop_id, sequence);
299
+ CREATE INDEX IF NOT EXISTS turns_timestamp ON turns (timestamp);
300
+
301
+ -- Provider calls are attempts beneath one engine turn. Rejected and interrupted
302
+ -- response evidence persists without becoming a turn or entering model-visible
303
+ -- history.
304
+ CREATE TABLE IF NOT EXISTS turn_attempts (
305
+ id INTEGER NOT NULL PRIMARY KEY,
306
+ turn_id INTEGER NOT NULL,
307
+ sequence INTEGER NOT NULL CHECK (sequence >= 1),
308
+ accepted INTEGER NOT NULL CHECK (accepted IN (0, 1)),
309
+ response TEXT NOT NULL CHECK (json_valid(response)),
310
+ parse_errors TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(parse_errors)),
311
+ -- Exact opaque tag set forwarded with this response-bearing provider call.
312
+ -- {§attribution}
313
+ attributions TEXT NOT NULL DEFAULT '[]' CHECK (
314
+ json_valid(attributions) AND json_type(attributions) = 'array'
315
+ ),
316
+ usage_prompt INTEGER NOT NULL DEFAULT 0 CHECK (usage_prompt >= 0),
317
+ usage_completion INTEGER NOT NULL DEFAULT 0 CHECK (usage_completion >= 0),
318
+ usage_reasoning INTEGER NOT NULL DEFAULT 0 CHECK (usage_reasoning >= 0),
319
+ usage_cached INTEGER NOT NULL DEFAULT 0 CHECK (usage_cached >= 0),
320
+ usage_cost TEXT NOT NULL CHECK (json_valid(usage_cost) AND json_type(usage_cost) = 'object'),
321
+ usage_cost_usd REAL CHECK (usage_cost_usd IS NULL OR usage_cost_usd >= 0),
322
+ finish_reason TEXT,
323
+ model TEXT NOT NULL CHECK (length(model) >= 1),
324
+ timestamp TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
325
+ UNIQUE (turn_id, sequence),
326
+ FOREIGN KEY (turn_id) REFERENCES turns(id) ON DELETE CASCADE
327
+ ) STRICT;
328
+
329
+ CREATE INDEX IF NOT EXISTS turn_attempts_turn_id ON turn_attempts (turn_id);
330
+ CREATE UNIQUE INDEX IF NOT EXISTS turn_attempts_one_accepted_per_turn
331
+ ON turn_attempts (turn_id)
332
+ WHERE accepted = 1;
333
+
334
+ -- derivations
335
+ -- Content-addressed deep projections. Entries point at a COMPLETE artifact by
336
+ -- deep_hash; graph, FTS, and vectors are stored once regardless of how many
337
+ -- workspace/worktree paths carry identical content under the same reader/config.
338
+ -- A building row is unattached and safely replaceable after interruption.
339
+ CREATE TABLE IF NOT EXISTS derivations (
340
+ id INTEGER NOT NULL PRIMARY KEY,
341
+ deep_hash TEXT NOT NULL UNIQUE CHECK (length(deep_hash) > 0),
342
+ state TEXT NOT NULL DEFAULT 'building' CHECK (state IN ('building', 'complete')),
343
+ disposition TEXT CHECK (disposition IN ('vector', 'lexical', 'excluded', 'nonsemantic', 'failed')),
344
+ reason TEXT,
345
+ CHECK ((state = 'building' AND disposition IS NULL) OR (state = 'complete' AND disposition IS NOT NULL))
346
+ ) STRICT;
347
+
348
+ -- entries
349
+ -- The canonical addressable store. (workspace, owner, scheme, pathname) is the identity
350
+ -- tuple, and NO component may be NULL: NULLs are distinct under SQL UNIQUE, so a nullable
351
+ -- component voids the identity index. Bare/file paths persist under the reserved `file`
352
+ -- scheme; they still render as bare paths. {§entry-identity-no-null}
353
+ CREATE TABLE IF NOT EXISTS entries (
354
+ id INTEGER NOT NULL PRIMARY KEY,
355
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
356
+ workspace_id INTEGER,
357
+ scheme TEXT NOT NULL CHECK (length(scheme) > 0),
358
+ pathname TEXT NOT NULL,
359
+ -- {§entry-owner} — every entry is owned by a worker: the spawning worker for capability
360
+ -- streams, the workspace's reserved 'commons' worker for shared content. A real row, never
361
+ -- NULL (NULLs are distinct under UNIQUE — a nullable owner would let the commons fragment).
362
+ -- The id never renders into a URI or packet; the model addresses owners by NAME (authority).
363
+ owner_id INTEGER NOT NULL,
364
+ -- Entry-private metadata. Prompt frames use `openPaths` to carry selected
365
+ -- workspace paths into the exact turn that publishes the frame
366
+ -- ({§methods-loop-run-open-paths}).
367
+ attributes TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attributes)),
368
+ -- SPEC {§membership} — how a file member entered the curated surface. 'git' rows are
369
+ -- reconciled against the repo's members each turn — tracked ls-files PLUS untracked-
370
+ -- but-not-ignored files ({§membership-auto-add}) — registered + un-registered so entries
371
+ -- == members; 'client'/'constraint' (model-created, add-glob) are not git's to reclaim.
372
+ -- NULL = not a file member (other schemes don't carry origin).
373
+ membership_origin TEXT CHECK (membership_origin IS NULL OR membership_origin IN ('git', 'client', 'constraint')),
374
+ -- {§membership-change-gated-sync}: hash of the body content at the last
375
+ -- deep-channel derivation. The manifest-add pass re-derives symbols/refs (and
376
+ -- embeddings, later) ONLY when this differs from the current body hash — an
377
+ -- unchanged entry is skipped, never re-metadatafied every turn.
378
+ deep_hash TEXT,
379
+ -- SPEC {§membership-change-gated-sync} — the per-member sync stat-detect:
380
+ -- "<mtimeMs>:<size>" of the disk file at its last materialization. The pre-turn
381
+ -- sync stat()s every member but re-reads/re-tokenizes/rewrites only one whose
382
+ -- signature changed; an unchanged member is a no-op. NULL = never synced.
383
+ synced_sig TEXT,
384
+ -- User Note 5 — manifest cache-friendliness. Last-modified stamp, bumped on every
385
+ -- channel write by entries_touch_on_channel_write; engine_list_workspace_entries orders
386
+ -- the catalog by it ASC so dormant entries hold the stable prompt-cache prefix.
387
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
388
+ CHECK (workspace_id IS NOT NULL),
389
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE,
390
+ FOREIGN KEY (owner_id) REFERENCES workers(id) ON DELETE CASCADE,
391
+ FOREIGN KEY (deep_hash) REFERENCES derivations(deep_hash)
392
+ ) STRICT;
393
+
394
+ -- {§entry-owner} / {§stream-owner-scoped} — owner is the sole visibility and identity axis.
395
+ -- Concurrent workers' capability streams share the loop-relative coordinate (every worker's first
396
+ -- loop is seq 1), so identity keys on the owner and identical coordinates are distinct rows
397
+ -- ({§stream-owner-scoped}).
398
+ CREATE UNIQUE INDEX IF NOT EXISTS entries_identity ON entries (workspace_id, owner_id, scheme, pathname);
399
+
400
+ -- The ONE engine-imposed constraint (SPEC {§stream-constraints}, {§stream-constraints-engine-one-cap}): 100 MiB char-length cap
401
+ -- per channel content body. All other limits are extrinsic.
402
+ CREATE TABLE IF NOT EXISTS entry_channels (
403
+ entry_id INTEGER NOT NULL,
404
+ name TEXT NOT NULL CHECK (length(name) > 0),
405
+ content TEXT NOT NULL CHECK (length(content) <= 104857600),
406
+ mimetype TEXT NOT NULL CHECK (length(mimetype) > 0),
407
+ tokens INTEGER NOT NULL DEFAULT 0 CHECK (tokens >= 0),
408
+ -- content identity: sha256 of content, stamped at static writes (streamed appends leave it
409
+ -- NULL). The per-tokenizer token cache it once keyed was retired — {§tokenomics-agnostic-ruler}.
410
+ content_hash TEXT,
411
+ state TEXT NOT NULL DEFAULT 'static' CHECK (state IN ('static', 'active', 'closed', 'errored')),
412
+ PRIMARY KEY (entry_id, name),
413
+ FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
414
+ ) STRICT, WITHOUT ROWID;
415
+
416
+ -- User Note 5 — bump the entry's updated_at on any channel write so the catalog
417
+ -- (ordered by updated_at ASC) keeps recently-touched entries at the tail and holds
418
+ -- the prompt-cache prefix stable across turns.
419
+ CREATE TRIGGER IF NOT EXISTS entries_touch_on_channel_write
420
+ AFTER INSERT ON entry_channels
421
+ BEGIN
422
+ UPDATE entries SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = NEW.entry_id;
423
+ END;
424
+
425
+ CREATE TABLE IF NOT EXISTS entry_tags (
426
+ entry_id INTEGER NOT NULL,
427
+ tag TEXT NOT NULL CHECK (length(tag) > 0),
428
+ PRIMARY KEY (entry_id, tag),
429
+ FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
430
+ ) STRICT, WITHOUT ROWID;
431
+
432
+ CREATE INDEX IF NOT EXISTS entry_tags_tag ON entry_tags (tag);
433
+
434
+ -- symbol_defs
435
+ -- @graph NODES ({§relation-indexed-dialects}). Code symbol definitions, populated
436
+ -- once per content-addressed derivation from mimetypes'
437
+ -- `symbols` channel. Qualified path = container ? container || '.' || name : name.
438
+ CREATE TABLE IF NOT EXISTS symbol_defs (
439
+ id INTEGER NOT NULL PRIMARY KEY,
440
+ derivation_id INTEGER NOT NULL,
441
+ name TEXT NOT NULL CHECK (length(name) > 0),
442
+ kind TEXT NOT NULL,
443
+ container TEXT,
444
+ line INTEGER NOT NULL,
445
+ end_line INTEGER,
446
+ FOREIGN KEY (derivation_id) REFERENCES derivations(id) ON DELETE CASCADE
447
+ ) STRICT;
448
+
449
+ CREATE INDEX IF NOT EXISTS symbol_defs_name ON symbol_defs (name);
450
+
451
+ -- symbol_refs
452
+ -- @graph EDGES ({§relation-indexed-dialects}), from mimetypes' `references` channel.
453
+ -- name = edge TARGET; container = the SOURCE def's full qualified path (the
454
+ -- @> join key; module-level → NULL); kind ∈ import|call|instantiate|inherit|
455
+ -- type|use (frozen, edge metadata only — traversal is kind-agnostic).
456
+ CREATE TABLE IF NOT EXISTS symbol_refs (
457
+ id INTEGER NOT NULL PRIMARY KEY,
458
+ derivation_id INTEGER NOT NULL,
459
+ name TEXT NOT NULL CHECK (length(name) > 0),
460
+ kind TEXT NOT NULL,
461
+ container TEXT,
462
+ line INTEGER NOT NULL,
463
+ col INTEGER,
464
+ FOREIGN KEY (derivation_id) REFERENCES derivations(id) ON DELETE CASCADE
465
+ ) STRICT;
466
+
467
+ CREATE INDEX IF NOT EXISTS symbol_refs_name ON symbol_refs (name);
468
+ CREATE INDEX IF NOT EXISTS symbol_refs_source ON symbol_refs (derivation_id, container);
469
+
470
+ -- derivation_fts (~semantic keyword fallback; {§relation-indexed-dialects})
471
+ -- Keyword/content index over a derivation's readable content; rowid IS derivations.id.
472
+ -- Explicit keyword fallback when no embedder is installed. Vector search never
473
+ -- consults this table: semantic recall is exhaustive over complete vectors.
474
+ CREATE VIRTUAL TABLE IF NOT EXISTS derivation_fts USING fts5(content);
475
+
476
+ -- derivation_embeddings (~semantic vectors; {§relation-indexed-dialects}).
477
+ -- One canonical wire vector ({§mimetype-embedding-wire}) per CHUNK: a derivation tiles into N chunks,
478
+ -- each addressed by its <L> line range (line_start..line_end) and embedded
479
+ -- separately, so a large body is fully searchable instead of truncated at the
480
+ -- embedder's window. line_start/line_end are stored for Project Findings to expose;
481
+ -- the rank currently max-pools a derivation's chunks, then projects every attached
482
+ -- pathname. semantic_rank exhaustively cosine-ranks these.
483
+ -- CASCADE-deleted with the derivation artifact.
484
+ CREATE TABLE IF NOT EXISTS derivation_embeddings (
485
+ derivation_id INTEGER NOT NULL,
486
+ chunk_seq INTEGER NOT NULL,
487
+ line_start INTEGER NOT NULL,
488
+ line_end INTEGER NOT NULL,
489
+ vector BLOB NOT NULL,
490
+ -- The model id that produced this vector (mimetypes' `embeddingModel`). Stored
491
+ -- per row as the dimension/staleness guard: rank filters by the current model so
492
+ -- a swap never cosine-compares mismatched dimensions.
493
+ embedding_model TEXT NOT NULL,
494
+ PRIMARY KEY (derivation_id, chunk_seq),
495
+ FOREIGN KEY (derivation_id) REFERENCES derivations(id) ON DELETE CASCADE
496
+ ) STRICT;
497
+
498
+ -- log_entries
499
+ -- Chronological event store. sequence is 1-based, scoped to the turn —
500
+ -- resets at each new turn. URI-bit columns are unprefixed (scheme,
501
+ -- pathname, …). state/outcome/attrs carry the proposal lifecycle —
502
+ -- status⊥state: status is the HTTP outcome, state is where in the
503
+ -- lifecycle the entry sits. Most rows write 'resolved' directly;
504
+ -- proposing schemes transition 'proposed' → resolved/failed/cancelled.
505
+ -- expanded: per-row visibility for OPEN/FOLD via the log:/// scheme.
506
+ CREATE TABLE IF NOT EXISTS log_entries (
507
+ id INTEGER NOT NULL PRIMARY KEY,
508
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
509
+
510
+ worker_id INTEGER NOT NULL,
511
+ loop_id INTEGER NOT NULL,
512
+ turn_id INTEGER NOT NULL,
513
+ sequence INTEGER NOT NULL CHECK (sequence >= 1),
514
+ at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
515
+ origin TEXT NOT NULL CHECK (origin IN ('model', 'client', 'plurnk', 'plugin')),
516
+ -- {§env-delta-attribution}: a worker:// name or stable subsystem token ('file');
517
+ -- NULL = the owning worker itself, rendered without causal attribution.
518
+ source TEXT,
519
+ -- Engine-owned occurrence identity. Source rows are stamped NULL→id by the
520
+ -- journal trigger; observer and fork copies carry it at insertion.
521
+ ambient_event_id INTEGER REFERENCES ambient_events(id),
522
+ -- Search derivation attached to this durable log result, when available.
523
+ deep_hash TEXT REFERENCES derivations(deep_hash),
524
+
525
+ -- 'error' is an ACTIONLESS row ({§operation-results} — errors are log items): a parse failure that
526
+ -- produced no op still records a log entry (op='error', status_rx≥400, no target) so the model
527
+ -- can fold/kill/recall its own mistakes like any other log row — one budget surface, the log.
528
+ -- 'model' is an ACTIONLESS row too ({§model-entry}): the model's own verbatim emission, mirrored
529
+ -- back as a foldable log item so it can finally SEE its prior output (born folded; the turn-0
530
+ -- exemplar is born open). text/vnd.plurnk-typed; OPEN/FOLD/KILL-able like any row.
531
+ -- No op enum here: the grammar op set is grammar's contract (PlurnkOp), and this column is written
532
+ -- only by the PlurnkOp-typed engine (grammar ops) or with the two service markers ('error','model').
533
+ -- A SQL enum would be a hand-copy of grammar's op list that silently goes stale on every new verb
534
+ -- (it did — FORK/WORK). Validity lives at the parse + type layer, not duplicated in DDL.
535
+ op TEXT NOT NULL,
536
+ suffix TEXT NOT NULL DEFAULT '',
537
+ signal TEXT CHECK (signal IS NULL OR json_valid(signal)),
538
+
539
+ scheme TEXT CHECK (scheme IS NULL OR length(scheme) > 0),
540
+ username TEXT,
541
+ password TEXT,
542
+ hostname TEXT,
543
+ port INTEGER CHECK (port IS NULL OR (port BETWEEN 0 AND 65535)),
544
+ pathname TEXT,
545
+ -- Serialized query without '?'; NULL = absent, '' = explicit empty. {§path-query}
546
+ query TEXT,
547
+ fragment TEXT,
548
+
549
+ lineMarker TEXT CHECK (lineMarker IS NULL OR json_valid(lineMarker)),
550
+
551
+ tx TEXT NOT NULL,
552
+ mimetype_tx TEXT NOT NULL CHECK (length(mimetype_tx) > 0),
553
+
554
+ rx TEXT NOT NULL,
555
+ mimetype_rx TEXT NOT NULL CHECK (length(mimetype_rx) > 0),
556
+ status_rx INTEGER NOT NULL CHECK (status_rx BETWEEN 100 AND 599),
557
+
558
+ tokens INTEGER NOT NULL DEFAULT 0 CHECK (tokens >= 0),
559
+
560
+ state TEXT NOT NULL DEFAULT 'resolved'
561
+ CHECK (state IN ('proposed', 'resolved', 'failed', 'cancelled')),
562
+ outcome TEXT,
563
+ attrs TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attrs)),
564
+
565
+ expanded INTEGER NOT NULL DEFAULT 1 CHECK (expanded IN (0, 1)),
566
+
567
+ FOREIGN KEY (worker_id) REFERENCES workers(id) ON DELETE CASCADE,
568
+ FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE,
569
+ FOREIGN KEY (turn_id) REFERENCES turns(id) ON DELETE CASCADE
570
+ ) STRICT;
571
+
572
+ CREATE UNIQUE INDEX IF NOT EXISTS log_entries_turn_id_sequence ON log_entries (turn_id, sequence);
573
+ CREATE INDEX IF NOT EXISTS log_entries_worker_id ON log_entries (worker_id);
574
+ CREATE INDEX IF NOT EXISTS log_entries_loop_id ON log_entries (loop_id);
575
+ CREATE INDEX IF NOT EXISTS log_entries_at ON log_entries (at);
576
+ CREATE UNIQUE INDEX IF NOT EXISTS log_entries_worker_ambient_event
577
+ ON log_entries (worker_id, ambient_event_id)
578
+ WHERE ambient_event_id IS NOT NULL;
579
+
580
+ -- {§log-region-tagging} — named log-region curation. FOLD is the log's write-op (EDIT can't
581
+ -- reach engine-written rows): FOLD[tag] stamps a tag on a region; OPEN[tag]/FIND[tag] filter
582
+ -- by it. Mirrors entry_tags (apply additive / filter ALL-tags AND); CASCADE with the row on KILL.
583
+ CREATE TABLE IF NOT EXISTS log_tags (
584
+ log_entry_id INTEGER NOT NULL,
585
+ tag TEXT NOT NULL CHECK (length(tag) > 0),
586
+ PRIMARY KEY (log_entry_id, tag),
587
+ FOREIGN KEY (log_entry_id) REFERENCES log_entries(id) ON DELETE CASCADE
588
+ ) STRICT, WITHOUT ROWID;
589
+
590
+ CREATE INDEX IF NOT EXISTS log_tags_tag ON log_tags (tag);
591
+
592
+ -- Column-scoped immutability: the original action's identity and target
593
+ -- never change; the proposal lifecycle is allowed to mutate state,
594
+ -- outcome, status_rx, rx, expanded.
595
+ CREATE TRIGGER IF NOT EXISTS log_entries_immutable_core
596
+ BEFORE UPDATE OF
597
+ worker_id, loop_id, turn_id, sequence, at, origin, source,
598
+ op, suffix, signal,
599
+ scheme, username, password, hostname,
600
+ port, pathname, query, fragment,
601
+ lineMarker, tx, mimetype_tx, mimetype_rx, attrs
602
+ ON log_entries
603
+ BEGIN
604
+ SELECT RAISE(ABORT, 'log_entries core fields are immutable; only state/outcome/status_rx/rx/expanded may change');
605
+ END;
606
+
607
+ -- The engine may stamp an originating row exactly once. No later reassignment
608
+ -- can sever or counterfeit the occurrence identity.
609
+ CREATE TRIGGER IF NOT EXISTS log_entries_ambient_event_once
610
+ BEFORE UPDATE OF ambient_event_id ON log_entries
611
+ WHEN NOT (OLD.ambient_event_id IS NULL AND NEW.ambient_event_id IS NOT NULL)
612
+ BEGIN
613
+ SELECT RAISE(ABORT, 'log_entries ambient event identity may only be assigned once');
614
+ END;
615
+
616
+ -- Immediate successful shared EDITs append their occurrence in the same SQL
617
+ -- statement that persists the receipt. Rows already carrying an event id are
618
+ -- observer/fork history and can never republish themselves.
619
+ CREATE TRIGGER IF NOT EXISTS log_entries_append_ambient_event_insert
620
+ AFTER INSERT ON log_entries
621
+ WHEN NEW.ambient_event_id IS NULL
622
+ AND NEW.op = 'EDIT'
623
+ AND NEW.state = 'resolved'
624
+ AND NEW.status_rx IN (200, 201)
625
+ AND (NEW.scheme IS NULL OR NEW.scheme != 'plurnk')
626
+ AND (NEW.scheme IS NULL OR NEW.scheme != 'worker' OR NEW.hostname IS NULL OR NEW.hostname = 'plurnk')
627
+ AND (
628
+ NEW.origin != 'plurnk'
629
+ OR EXISTS (SELECT 1 FROM workers w WHERE w.id = NEW.worker_id AND w.name = 'plurnk')
630
+ )
631
+ BEGIN
632
+ INSERT INTO ambient_events (
633
+ workspace_id, producer_worker_id, kind, source_record_id, source,
634
+ op, scheme, hostname, pathname, rx, attrs, status_rx
635
+ )
636
+ SELECT w.workspace_id, NEW.worker_id, 'edit', NEW.id, NEW.source,
637
+ 'EDIT', NEW.scheme, NEW.hostname, NEW.pathname, NEW.rx, NEW.attrs, NEW.status_rx
638
+ FROM workers w
639
+ WHERE w.id = NEW.worker_id;
640
+ UPDATE log_entries SET ambient_event_id = last_insert_rowid() WHERE id = NEW.id;
641
+ END;
642
+
643
+ -- A proposed EDIT becomes an occurrence only when its one lifecycle transition
644
+ -- resolves successfully. Rejection, cancellation, and failed application publish nothing.
645
+ CREATE TRIGGER IF NOT EXISTS log_entries_append_ambient_event_resolve
646
+ AFTER UPDATE OF state, status_rx ON log_entries
647
+ WHEN OLD.state = 'proposed'
648
+ AND NEW.state = 'resolved'
649
+ AND NEW.ambient_event_id IS NULL
650
+ AND NEW.op = 'EDIT'
651
+ AND NEW.status_rx IN (200, 201)
652
+ AND (NEW.scheme IS NULL OR NEW.scheme != 'plurnk')
653
+ AND (NEW.scheme IS NULL OR NEW.scheme != 'worker' OR NEW.hostname IS NULL OR NEW.hostname = 'plurnk')
654
+ AND (
655
+ NEW.origin != 'plurnk'
656
+ OR EXISTS (SELECT 1 FROM workers w WHERE w.id = NEW.worker_id AND w.name = 'plurnk')
657
+ )
658
+ BEGIN
659
+ INSERT INTO ambient_events (
660
+ workspace_id, producer_worker_id, kind, source_record_id, source,
661
+ op, scheme, hostname, pathname, rx, attrs, status_rx
662
+ )
663
+ SELECT w.workspace_id, NEW.worker_id, 'edit', NEW.id, NEW.source,
664
+ 'EDIT', NEW.scheme, NEW.hostname, NEW.pathname, NEW.rx, NEW.attrs, NEW.status_rx
665
+ FROM workers w
666
+ WHERE w.id = NEW.worker_id;
667
+ UPDATE log_entries SET ambient_event_id = last_insert_rowid() WHERE id = NEW.id;
668
+ END;
669
+
670
+ -- cost_rollups
671
+ -- Triggers maintaining denormalized USD totals on workers and workspaces
672
+ -- as turns insert/update. Pure denormalization (textbook trigger use);
673
+ -- no branching state-machine logic lives here.
674
+ CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_insert_worker
675
+ AFTER INSERT ON turns
676
+ BEGIN
677
+ UPDATE workers
678
+ SET cost_usd = (
679
+ SELECT CASE WHEN COUNT(*) FILTER (WHERE t.usage_cost_usd IS NULL) > 0
680
+ THEN NULL ELSE COALESCE(SUM(t.usage_cost_usd), 0) END
681
+ FROM turns t JOIN loops l ON l.id = t.loop_id
682
+ WHERE l.worker_id = workers.id
683
+ )
684
+ WHERE id = (SELECT worker_id FROM loops WHERE id = NEW.loop_id);
685
+ END;
686
+
687
+ CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_insert_workspace
688
+ AFTER INSERT ON turns
689
+ BEGIN
690
+ UPDATE workspaces
691
+ SET cost_usd = (
692
+ SELECT CASE WHEN COUNT(*) FILTER (WHERE t.usage_cost_usd IS NULL) > 0
693
+ THEN NULL ELSE COALESCE(SUM(t.usage_cost_usd), 0) END
694
+ FROM turns t
695
+ JOIN loops l ON l.id = t.loop_id
696
+ JOIN workers r ON r.id = l.worker_id
697
+ WHERE r.workspace_id = workspaces.id
698
+ )
699
+ WHERE id = (
700
+ SELECT r.workspace_id
701
+ FROM workers r
702
+ JOIN loops l ON l.worker_id = r.id
703
+ WHERE l.id = NEW.loop_id
704
+ );
705
+ END;
706
+
707
+ CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_update_worker
708
+ AFTER UPDATE OF usage_cost_usd ON turns
709
+ WHEN NEW.usage_cost_usd IS NOT OLD.usage_cost_usd
710
+ BEGIN
711
+ UPDATE workers
712
+ SET cost_usd = (
713
+ SELECT CASE WHEN COUNT(*) FILTER (WHERE t.usage_cost_usd IS NULL) > 0
714
+ THEN NULL ELSE COALESCE(SUM(t.usage_cost_usd), 0) END
715
+ FROM turns t JOIN loops l ON l.id = t.loop_id
716
+ WHERE l.worker_id = workers.id
717
+ )
718
+ WHERE id = (SELECT worker_id FROM loops WHERE id = NEW.loop_id);
719
+ END;
720
+
721
+ CREATE TRIGGER IF NOT EXISTS turns_cost_rollup_update_workspace
722
+ AFTER UPDATE OF usage_cost_usd ON turns
723
+ WHEN NEW.usage_cost_usd IS NOT OLD.usage_cost_usd
724
+ BEGIN
725
+ UPDATE workspaces
726
+ SET cost_usd = (
727
+ SELECT CASE WHEN COUNT(*) FILTER (WHERE t.usage_cost_usd IS NULL) > 0
728
+ THEN NULL ELSE COALESCE(SUM(t.usage_cost_usd), 0) END
729
+ FROM turns t
730
+ JOIN loops l ON l.id = t.loop_id
731
+ JOIN workers r ON r.id = l.worker_id
732
+ WHERE r.workspace_id = workspaces.id
733
+ )
734
+ WHERE id = (
735
+ SELECT r.workspace_id
736
+ FROM workers r
737
+ JOIN loops l ON l.worker_id = r.id
738
+ WHERE l.id = NEW.loop_id
739
+ );
740
+ END;
741
+
742
+ -- subscriptions
743
+ -- Durable subscription lifecycle per SPEC {§subscriptions}. The row records what
744
+ -- the worker holds and routes cancellation to a separate process-local callable;
745
+ -- it never serializes that callable. Closed rows persist for forensics; partial
746
+ -- unique index enforces one active subscription per (worker, entry).
747
+ CREATE TABLE IF NOT EXISTS subscriptions (
748
+ id INTEGER NOT NULL PRIMARY KEY,
749
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
750
+ worker_id INTEGER NOT NULL,
751
+ entry_id INTEGER NOT NULL,
752
+ scheme TEXT NOT NULL CHECK (length(scheme) > 0),
753
+ handle TEXT NOT NULL CHECK (length(handle) > 0),
754
+ published_channel TEXT CHECK (published_channel IS NULL OR length(published_channel) > 0),
755
+ opened_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
756
+ -- EXEC `<T,P>` poll policy: NULL = default backoff, 0 = disabled, positive = fixed cadence.
757
+ -- While the owning loop hibernates (202), an armed policy wakes it to inspect the stream ({§exec-poll}).
758
+ poll_seconds INTEGER CHECK (poll_seconds IS NULL OR poll_seconds >= 0),
759
+ -- EXEC `<0>` — turn-scoped: the stream is reaped at the worker's next pre-turn so it never survives
760
+ -- into the subsequent turn; its terminal output surfaces born-OPEN like any conclusion. {§exec-poll}
761
+ turn_scoped INTEGER NOT NULL DEFAULT 0 CHECK (turn_scoped IN (0, 1)),
762
+ closed_at TEXT,
763
+ close_status INTEGER CHECK (close_status IS NULL OR (close_status BETWEEN 100 AND 599)),
764
+ close_result TEXT CHECK (close_result IS NULL OR json_valid(close_result)),
765
+ CHECK ((closed_at IS NULL AND close_status IS NULL)
766
+ OR (closed_at IS NOT NULL AND close_status IS NOT NULL)),
767
+ FOREIGN KEY (worker_id) REFERENCES workers(id) ON DELETE CASCADE,
768
+ FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
769
+ ) STRICT;
770
+
771
+ CREATE UNIQUE INDEX IF NOT EXISTS subscriptions_active_one_per_entry
772
+ ON subscriptions (worker_id, entry_id)
773
+ WHERE closed_at IS NULL;
774
+
775
+ CREATE INDEX IF NOT EXISTS subscriptions_scheme_active
776
+ ON subscriptions (scheme)
777
+ WHERE closed_at IS NULL;
778
+
779
+ CREATE INDEX IF NOT EXISTS subscriptions_opened_at ON subscriptions (opened_at);
780
+
781
+ CREATE TRIGGER IF NOT EXISTS subscriptions_result_contract_insert
782
+ BEFORE INSERT ON subscriptions
783
+ WHEN NOT (
784
+ (NEW.closed_at IS NULL AND NEW.close_status IS NULL AND NEW.close_result IS NULL)
785
+ OR (
786
+ NEW.closed_at IS NOT NULL
787
+ AND NEW.close_status IS NOT NULL
788
+ AND NEW.close_result IS NOT NULL
789
+ AND json_valid(NEW.close_result)
790
+ AND json_type(NEW.close_result, '$.status') = 'integer'
791
+ AND json_extract(NEW.close_result, '$.status') = NEW.close_status
792
+ AND (
793
+ (NEW.close_status < 400 AND json_type(NEW.close_result, '$.problem') IS NULL)
794
+ OR (
795
+ NEW.close_status >= 400
796
+ AND json_type(NEW.close_result, '$.problem') = 'object'
797
+ AND json_extract(NEW.close_result, '$.problem.status') = NEW.close_status
798
+ )
799
+ )
800
+ )
801
+ )
802
+ BEGIN
803
+ SELECT RAISE(ABORT, 'subscription terminal result violates the operation-result contract');
804
+ END;
805
+
806
+ CREATE TRIGGER IF NOT EXISTS subscriptions_result_contract_update
807
+ BEFORE UPDATE OF closed_at, close_status, close_result ON subscriptions
808
+ WHEN NOT (
809
+ (NEW.closed_at IS NULL AND NEW.close_status IS NULL AND NEW.close_result IS NULL)
810
+ OR (
811
+ NEW.closed_at IS NOT NULL
812
+ AND NEW.close_status IS NOT NULL
813
+ AND NEW.close_result IS NOT NULL
814
+ AND json_valid(NEW.close_result)
815
+ AND json_type(NEW.close_result, '$.status') = 'integer'
816
+ AND json_extract(NEW.close_result, '$.status') = NEW.close_status
817
+ AND (
818
+ (NEW.close_status < 400 AND json_type(NEW.close_result, '$.problem') IS NULL)
819
+ OR (
820
+ NEW.close_status >= 400
821
+ AND json_type(NEW.close_result, '$.problem') = 'object'
822
+ AND json_extract(NEW.close_result, '$.problem.status') = NEW.close_status
823
+ )
824
+ )
825
+ )
826
+ )
827
+ BEGIN
828
+ SELECT RAISE(ABORT, 'subscription terminal result violates the operation-result contract');
829
+ END;
830
+
831
+ -- (worker_watermarks removed — {§env-delta} is now pull-from-log, no per-worker snapshot.)
832
+
833
+ -- workspace_constraints
834
+ -- SPEC {§membership} constraint overlay — the client's supersede over git membership.
835
+ -- Per (workspace, effect, glob/target): `pick` (members git misses, resolved by a
836
+ -- targeted client-dictated scan), `hide` (drop git-tracked matches), `view` (member
837
+ -- for read; File.edit rejects the write). git-absent, `pick` rows are the sole substrate
838
+ -- source. Composed at membership resolution; node:path.matchesGlob.
839
+ CREATE TABLE IF NOT EXISTS workspace_constraints (
840
+ workspace_id INTEGER NOT NULL,
841
+ effect TEXT NOT NULL CHECK (effect IN ('pick', 'hide', 'view')),
842
+ glob TEXT NOT NULL,
843
+ PRIMARY KEY (workspace_id, effect, glob),
844
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
845
+ ) STRICT, WITHOUT ROWID;
846
+
847
+ -- A branch batch is a durable exclusive transaction over the privileged
848
+ -- project repository.
849
+ CREATE TABLE IF NOT EXISTS branch_batches (
850
+ id INTEGER NOT NULL PRIMARY KEY,
851
+ workspace_id INTEGER NOT NULL,
852
+ parent_worker_id INTEGER NOT NULL,
853
+ parent_loop_id INTEGER NOT NULL,
854
+ parent_turn_id INTEGER NOT NULL UNIQUE,
855
+ state TEXT NOT NULL DEFAULT 'collecting'
856
+ CHECK (state IN ('collecting', 'queued', 'running', 'completed', 'failed', 'recovery_required')),
857
+ active_sequence INTEGER CHECK (active_sequence IS NULL OR active_sequence >= 1),
858
+ repository_path TEXT CHECK (repository_path IS NULL OR length(repository_path) > 0),
859
+ original_ref TEXT,
860
+ original_commit TEXT CHECK (original_commit IS NULL OR length(original_commit) > 0),
861
+ problem TEXT CHECK (problem IS NULL OR json_valid(problem)),
862
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
863
+ completed_at TEXT,
864
+ CHECK (
865
+ (repository_path IS NULL AND original_commit IS NULL)
866
+ OR (repository_path IS NOT NULL AND original_commit IS NOT NULL)
867
+ ),
868
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE,
869
+ FOREIGN KEY (parent_worker_id) REFERENCES workers(id) ON DELETE CASCADE,
870
+ FOREIGN KEY (parent_loop_id) REFERENCES loops(id) ON DELETE CASCADE,
871
+ FOREIGN KEY (parent_turn_id) REFERENCES turns(id) ON DELETE CASCADE
872
+ ) STRICT;
873
+
874
+ CREATE UNIQUE INDEX IF NOT EXISTS branch_batches_one_active_per_workspace
875
+ ON branch_batches (workspace_id)
876
+ WHERE state IN ('collecting', 'queued', 'running', 'recovery_required');
877
+
878
+ CREATE TABLE IF NOT EXISTS branch_batch_items (
879
+ id INTEGER NOT NULL PRIMARY KEY,
880
+ batch_id INTEGER NOT NULL,
881
+ sequence INTEGER NOT NULL CHECK (sequence >= 1),
882
+ worker_id INTEGER NOT NULL,
883
+ loop_id INTEGER NOT NULL,
884
+ branch TEXT NOT NULL CHECK (length(branch) > 0),
885
+ state TEXT NOT NULL DEFAULT 'queued'
886
+ CHECK (state IN ('queued', 'running', 'succeeded', 'failed', 'recovery_required')),
887
+ result TEXT CHECK (result IS NULL OR json_valid(result)),
888
+ result_commit TEXT CHECK (result_commit IS NULL OR length(result_commit) > 0),
889
+ changed INTEGER CHECK (changed IS NULL OR changed IN (0, 1)),
890
+ started_at TEXT,
891
+ completed_at TEXT,
892
+ UNIQUE (batch_id, sequence),
893
+ UNIQUE (batch_id, branch),
894
+ FOREIGN KEY (batch_id) REFERENCES branch_batches(id) ON DELETE CASCADE,
895
+ FOREIGN KEY (worker_id) REFERENCES workers(id) ON DELETE CASCADE,
896
+ FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE
897
+ ) STRICT;