@plurnk/plurnk-service 1.18.0 → 1.19.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 (447) hide show
  1. package/.env.defaults +76 -13
  2. package/README.md +5 -3
  3. package/SPEC.md +924 -689
  4. package/dist/Paths.js +3 -3
  5. package/dist/build-info.json +1 -1
  6. package/dist/content/body-preview.d.ts +1 -0
  7. package/dist/content/body-preview.d.ts.map +1 -1
  8. package/dist/content/body-preview.js +8 -10
  9. package/dist/content/body-preview.js.map +1 -1
  10. package/dist/content/edit-receipt.d.ts.map +1 -1
  11. package/dist/content/edit-receipt.js +30 -29
  12. package/dist/content/edit-receipt.js.map +1 -1
  13. package/dist/content/line-anchors.d.ts.map +1 -1
  14. package/dist/content/line-anchors.js +17 -5
  15. package/dist/content/line-anchors.js.map +1 -1
  16. package/dist/content/read-projector.d.ts +2 -2
  17. package/dist/content/read-projector.d.ts.map +1 -1
  18. package/dist/content/read-projector.js +79 -37
  19. package/dist/content/read-projector.js.map +1 -1
  20. package/dist/content/scope-format.d.ts +9 -0
  21. package/dist/content/scope-format.d.ts.map +1 -0
  22. package/dist/content/scope-format.js +28 -0
  23. package/dist/content/scope-format.js.map +1 -0
  24. package/dist/core/AdministrativeLoop.d.ts +8 -0
  25. package/dist/core/AdministrativeLoop.d.ts.map +1 -0
  26. package/dist/core/AdministrativeLoop.js +16 -0
  27. package/dist/core/AdministrativeLoop.js.map +1 -0
  28. package/dist/core/AdmittedTurnExecutor.d.ts +2 -1
  29. package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
  30. package/dist/core/AdmittedTurnExecutor.js +19 -19
  31. package/dist/core/AdmittedTurnExecutor.js.map +1 -1
  32. package/dist/core/BareBatchRunner.d.ts +1 -2
  33. package/dist/core/BareBatchRunner.d.ts.map +1 -1
  34. package/dist/core/BareBatchRunner.js +7 -12
  35. package/dist/core/BareBatchRunner.js.map +1 -1
  36. package/dist/core/BudgetReadout.d.ts.map +1 -1
  37. package/dist/core/BudgetReadout.js +3 -4
  38. package/dist/core/BudgetReadout.js.map +1 -1
  39. package/dist/core/CapabilityPolicies.d.ts +4 -2
  40. package/dist/core/CapabilityPolicies.d.ts.map +1 -1
  41. package/dist/core/CapabilityPolicies.js +23 -2
  42. package/dist/core/CapabilityPolicies.js.map +1 -1
  43. package/dist/core/CapabilityResolver.d.ts +2 -2
  44. package/dist/core/CapabilityResolver.d.ts.map +1 -1
  45. package/dist/core/CapabilityResolver.js +6 -3
  46. package/dist/core/CapabilityResolver.js.map +1 -1
  47. package/dist/core/ChannelWrite.d.ts +3 -6
  48. package/dist/core/ChannelWrite.d.ts.map +1 -1
  49. package/dist/core/ChannelWrite.js +8 -8
  50. package/dist/core/ChannelWrite.js.map +1 -1
  51. package/dist/core/ChannelWrite.sql +17 -11
  52. package/dist/core/ClientInteractions.d.ts +11 -1
  53. package/dist/core/ClientInteractions.d.ts.map +1 -1
  54. package/dist/core/ClientInteractions.js +26 -2
  55. package/dist/core/ClientInteractions.js.map +1 -1
  56. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  57. package/dist/core/CoreSchemeServices.js +1 -0
  58. package/dist/core/CoreSchemeServices.js.map +1 -1
  59. package/dist/core/DataStatementRunner.js +6 -6
  60. package/dist/core/DataStatementRunner.js.map +1 -1
  61. package/dist/core/Dispatcher.d.ts +12 -4
  62. package/dist/core/Dispatcher.d.ts.map +1 -1
  63. package/dist/core/Dispatcher.js +112 -90
  64. package/dist/core/Dispatcher.js.map +1 -1
  65. package/dist/core/Dispatcher.sql +11 -26
  66. package/dist/core/DurableStatement.d.ts +4 -1
  67. package/dist/core/DurableStatement.d.ts.map +1 -1
  68. package/dist/core/DurableStatement.js +4 -4
  69. package/dist/core/DurableStatement.js.map +1 -1
  70. package/dist/core/EditMutations.d.ts.map +1 -1
  71. package/dist/core/EditMutations.js +5 -2
  72. package/dist/core/EditMutations.js.map +1 -1
  73. package/dist/core/Engine.d.ts +11 -9
  74. package/dist/core/Engine.d.ts.map +1 -1
  75. package/dist/core/Engine.js +27 -65
  76. package/dist/core/Engine.js.map +1 -1
  77. package/dist/core/Engine.sql +2 -22
  78. package/dist/core/EnvFlags.d.ts.map +1 -1
  79. package/dist/core/EnvFlags.js +4 -2
  80. package/dist/core/EnvFlags.js.map +1 -1
  81. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  82. package/dist/core/ExecutorRegistry.js +2 -1
  83. package/dist/core/ExecutorRegistry.js.map +1 -1
  84. package/dist/core/KillHandler.d.ts.map +1 -1
  85. package/dist/core/KillHandler.js +7 -12
  86. package/dist/core/KillHandler.js.map +1 -1
  87. package/dist/core/Knob.d.ts +9 -0
  88. package/dist/core/Knob.d.ts.map +1 -0
  89. package/dist/core/Knob.js +50 -0
  90. package/dist/core/Knob.js.map +1 -0
  91. package/dist/core/LogBody.d.ts.map +1 -1
  92. package/dist/core/LogBody.js +6 -35
  93. package/dist/core/LogBody.js.map +1 -1
  94. package/dist/core/LogEntryProjection.d.ts.map +1 -1
  95. package/dist/core/LogEntryProjection.js +4 -0
  96. package/dist/core/LogEntryProjection.js.map +1 -1
  97. package/dist/core/LogVisibility.d.ts.map +1 -1
  98. package/dist/core/LogVisibility.js +2 -1
  99. package/dist/core/LogVisibility.js.map +1 -1
  100. package/dist/core/LogWriter.js +2 -2
  101. package/dist/core/LogWriter.js.map +1 -1
  102. package/dist/core/LoopDriver.d.ts +1 -1
  103. package/dist/core/LoopDriver.d.ts.map +1 -1
  104. package/dist/core/LoopDriver.js +23 -29
  105. package/dist/core/LoopDriver.js.map +1 -1
  106. package/dist/core/LoopLifecycle.d.ts +4 -17
  107. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  108. package/dist/core/LoopLifecycle.js +20 -22
  109. package/dist/core/LoopLifecycle.js.map +1 -1
  110. package/dist/core/LoopLifecycle.sql +36 -49
  111. package/dist/core/LoopOutcome.d.ts +10 -0
  112. package/dist/core/LoopOutcome.d.ts.map +1 -0
  113. package/dist/core/LoopOutcome.js +28 -0
  114. package/dist/core/LoopOutcome.js.map +1 -0
  115. package/dist/core/LoopPolicies.d.ts +7 -0
  116. package/dist/core/LoopPolicies.d.ts.map +1 -0
  117. package/dist/core/LoopPolicies.js +37 -0
  118. package/dist/core/LoopPolicies.js.map +1 -0
  119. package/dist/core/MessageResources.d.ts +15 -0
  120. package/dist/core/MessageResources.d.ts.map +1 -0
  121. package/dist/core/MessageResources.js +46 -0
  122. package/dist/core/MessageResources.js.map +1 -0
  123. package/dist/core/MessageResources.sql +36 -0
  124. package/dist/core/OperatorConfig.d.ts +2 -1
  125. package/dist/core/OperatorConfig.d.ts.map +1 -1
  126. package/dist/core/OperatorConfig.js +14 -6
  127. package/dist/core/OperatorConfig.js.map +1 -1
  128. package/dist/core/PacketBuilder.d.ts.map +1 -1
  129. package/dist/core/PacketBuilder.js +20 -35
  130. package/dist/core/PacketBuilder.js.map +1 -1
  131. package/dist/core/PacketBuilder.sql +24 -6
  132. package/dist/core/PatternSelection.d.ts +1 -1
  133. package/dist/core/PatternSelection.d.ts.map +1 -1
  134. package/dist/core/ProposalLifecycle.d.ts +3 -1
  135. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  136. package/dist/core/ProposalLifecycle.js +85 -22
  137. package/dist/core/ProposalLifecycle.js.map +1 -1
  138. package/dist/core/ProviderInstantiate.d.ts +1 -0
  139. package/dist/core/ProviderInstantiate.d.ts.map +1 -1
  140. package/dist/core/ProviderInstantiate.js +12 -7
  141. package/dist/core/ProviderInstantiate.js.map +1 -1
  142. package/dist/core/ReasoningView.d.ts +1 -2
  143. package/dist/core/ReasoningView.d.ts.map +1 -1
  144. package/dist/core/ReasoningView.js +9 -20
  145. package/dist/core/ReasoningView.js.map +1 -1
  146. package/dist/core/ResourceBindings.d.ts.map +1 -1
  147. package/dist/core/ResourceBindings.js +5 -4
  148. package/dist/core/ResourceBindings.js.map +1 -1
  149. package/dist/core/ResourceMutations.d.ts +4 -4
  150. package/dist/core/ResourceMutations.d.ts.map +1 -1
  151. package/dist/core/ResourceMutations.js +2 -3
  152. package/dist/core/ResourceMutations.js.map +1 -1
  153. package/dist/core/ResourceSelector.d.ts +10 -3
  154. package/dist/core/ResourceSelector.d.ts.map +1 -1
  155. package/dist/core/ResourceSelector.js +52 -13
  156. package/dist/core/ResourceSelector.js.map +1 -1
  157. package/dist/core/ResourceTransfers.d.ts.map +1 -1
  158. package/dist/core/ResourceTransfers.js +4 -2
  159. package/dist/core/ResourceTransfers.js.map +1 -1
  160. package/dist/core/SchemeRegistry.d.ts +2 -0
  161. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  162. package/dist/core/SchemeRegistry.js +11 -5
  163. package/dist/core/SchemeRegistry.js.map +1 -1
  164. package/dist/core/StoredPacket.d.ts +3 -1
  165. package/dist/core/StoredPacket.d.ts.map +1 -1
  166. package/dist/core/StoredPacket.js +7 -3
  167. package/dist/core/StoredPacket.js.map +1 -1
  168. package/dist/core/StrikeRail.d.ts.map +1 -1
  169. package/dist/core/StrikeRail.js +9 -3
  170. package/dist/core/StrikeRail.js.map +1 -1
  171. package/dist/core/TerminalResult.d.ts +2 -2
  172. package/dist/core/TerminalResult.d.ts.map +1 -1
  173. package/dist/core/TerminalResult.js +15 -8
  174. package/dist/core/TerminalResult.js.map +1 -1
  175. package/dist/core/ToolInputSchema.d.ts.map +1 -1
  176. package/dist/core/ToolInputSchema.js +24 -8
  177. package/dist/core/ToolInputSchema.js.map +1 -1
  178. package/dist/core/ToolResources.d.ts +1 -0
  179. package/dist/core/ToolResources.d.ts.map +1 -1
  180. package/dist/core/ToolResources.js +45 -23
  181. package/dist/core/ToolResources.js.map +1 -1
  182. package/dist/core/Turn.d.ts +3 -1
  183. package/dist/core/Turn.d.ts.map +1 -1
  184. package/dist/core/Turn.js +4 -1
  185. package/dist/core/Turn.js.map +1 -1
  186. package/dist/core/Turn.sql +14 -2
  187. package/dist/core/TurnDispositionHandler.d.ts +13 -21
  188. package/dist/core/TurnDispositionHandler.d.ts.map +1 -1
  189. package/dist/core/TurnDispositionHandler.js +32 -190
  190. package/dist/core/TurnDispositionHandler.js.map +1 -1
  191. package/dist/core/TurnMaterialization.d.ts +9 -7
  192. package/dist/core/TurnMaterialization.d.ts.map +1 -1
  193. package/dist/core/TurnMaterialization.js +63 -41
  194. package/dist/core/TurnMaterialization.js.map +1 -1
  195. package/dist/core/TurnMaterialization.sql +23 -6
  196. package/dist/core/TurnOps.js +1 -1
  197. package/dist/core/TurnRunner.d.ts +1 -3
  198. package/dist/core/TurnRunner.d.ts.map +1 -1
  199. package/dist/core/TurnRunner.js +148 -189
  200. package/dist/core/TurnRunner.js.map +1 -1
  201. package/dist/core/TurnRunner.sql +1 -24
  202. package/dist/core/TurnSources.sql +42 -11
  203. package/dist/core/WorkerName.d.ts +1 -1
  204. package/dist/core/WorkerName.d.ts.map +1 -1
  205. package/dist/core/WorkerName.js +3 -3
  206. package/dist/core/WorkerName.js.map +1 -1
  207. package/dist/core/ambient.sql +45 -19
  208. package/dist/core/attachments.d.ts +3 -1
  209. package/dist/core/attachments.d.ts.map +1 -1
  210. package/dist/core/attachments.js +4 -0
  211. package/dist/core/attachments.js.map +1 -1
  212. package/dist/core/caps/CoreInteractionCaps.d.ts +1 -1
  213. package/dist/core/caps/CoreInteractionCaps.d.ts.map +1 -1
  214. package/dist/core/caps/CoreInteractionCaps.js +4 -2
  215. package/dist/core/caps/CoreInteractionCaps.js.map +1 -1
  216. package/dist/core/caps/DbChannelCaps.js +6 -6
  217. package/dist/core/caps/DbChannelCaps.js.map +1 -1
  218. package/dist/core/caps/DbEntryCaps.js +1 -1
  219. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  220. package/dist/core/caps/DbMessageCaps.d.ts +10 -0
  221. package/dist/core/caps/DbMessageCaps.d.ts.map +1 -0
  222. package/dist/core/caps/DbMessageCaps.js +39 -0
  223. package/dist/core/caps/DbMessageCaps.js.map +1 -0
  224. package/dist/core/caps/DbProjectionCaps.d.ts +2 -2
  225. package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
  226. package/dist/core/caps/DbProjectionCaps.js +10 -4
  227. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  228. package/dist/core/caps/SchemeCtxImpl.d.ts +3 -1
  229. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
  230. package/dist/core/caps/SchemeCtxImpl.js +11 -0
  231. package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
  232. package/dist/core/fork.sql +7 -6
  233. package/dist/core/git-state.d.ts +3 -2
  234. package/dist/core/git-state.d.ts.map +1 -1
  235. package/dist/core/git-state.js +37 -20
  236. package/dist/core/git-state.js.map +1 -1
  237. package/dist/core/packet-inject.js +1 -1
  238. package/dist/core/packet-wire.d.ts +11 -0
  239. package/dist/core/packet-wire.d.ts.map +1 -1
  240. package/dist/core/packet-wire.js +112 -88
  241. package/dist/core/packet-wire.js.map +1 -1
  242. package/dist/core/plurnk-uri.d.ts +4 -5
  243. package/dist/core/plurnk-uri.d.ts.map +1 -1
  244. package/dist/core/plurnk-uri.js +10 -31
  245. package/dist/core/plurnk-uri.js.map +1 -1
  246. package/dist/core/scheme-types.d.ts +3 -1
  247. package/dist/core/scheme-types.d.ts.map +1 -1
  248. package/dist/core/scheme-types.js +1 -1
  249. package/dist/core/scheme-types.js.map +1 -1
  250. package/dist/core/teaching.d.ts.map +1 -1
  251. package/dist/core/teaching.js +2 -1
  252. package/dist/core/teaching.js.map +1 -1
  253. package/dist/core/types.d.ts +1 -2
  254. package/dist/core/types.d.ts.map +1 -1
  255. package/dist/core/types.js +1 -1
  256. package/dist/core/types.js.map +1 -1
  257. package/dist/core/worker-ops.sql +3 -8
  258. package/dist/digest/Digest.d.ts.map +1 -1
  259. package/dist/digest/Digest.js +35 -30
  260. package/dist/digest/Digest.js.map +1 -1
  261. package/dist/digest/DigestRender.d.ts +1 -0
  262. package/dist/digest/DigestRender.d.ts.map +1 -1
  263. package/dist/digest/DigestRender.js +53 -1
  264. package/dist/digest/DigestRender.js.map +1 -1
  265. package/dist/digest/DigestRequiem.d.ts.map +1 -1
  266. package/dist/digest/DigestRequiem.js +13 -15
  267. package/dist/digest/DigestRequiem.js.map +1 -1
  268. package/dist/digest/digest-db.d.ts +3 -0
  269. package/dist/digest/digest-db.d.ts.map +1 -0
  270. package/dist/digest/digest-db.js +68 -0
  271. package/dist/digest/digest-db.js.map +1 -0
  272. package/dist/digest/digest-paths.d.ts +6 -0
  273. package/dist/digest/digest-paths.d.ts.map +1 -0
  274. package/dist/digest/digest-paths.js +23 -0
  275. package/dist/digest/digest-paths.js.map +1 -0
  276. package/dist/digest/digest-rows.d.ts +15 -0
  277. package/dist/digest/digest-rows.d.ts.map +1 -1
  278. package/dist/digest/digest.sql +13 -3
  279. package/dist/index.d.ts +0 -1
  280. package/dist/index.d.ts.map +1 -1
  281. package/dist/index.js +0 -1
  282. package/dist/index.js.map +1 -1
  283. package/dist/observe/genai.d.ts +2 -2
  284. package/dist/observe/genai.d.ts.map +1 -1
  285. package/dist/observe/genai.js +15 -5
  286. package/dist/observe/genai.js.map +1 -1
  287. package/dist/schemes/EffectPolicy.d.ts +0 -2
  288. package/dist/schemes/EffectPolicy.d.ts.map +1 -1
  289. package/dist/schemes/EffectPolicy.js +25 -36
  290. package/dist/schemes/EffectPolicy.js.map +1 -1
  291. package/dist/schemes/Exec.d.ts +4 -5
  292. package/dist/schemes/Exec.d.ts.map +1 -1
  293. package/dist/schemes/Exec.js +74 -62
  294. package/dist/schemes/Exec.js.map +1 -1
  295. package/dist/schemes/ExecOutputScheme.d.ts +6 -5
  296. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  297. package/dist/schemes/ExecOutputScheme.js +49 -16
  298. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  299. package/dist/schemes/File.d.ts.map +1 -1
  300. package/dist/schemes/File.js +28 -20
  301. package/dist/schemes/File.js.map +1 -1
  302. package/dist/schemes/Log.d.ts +4 -4
  303. package/dist/schemes/Log.d.ts.map +1 -1
  304. package/dist/schemes/Log.js +29 -9
  305. package/dist/schemes/Log.js.map +1 -1
  306. package/dist/schemes/QuestionTool.d.ts.map +1 -1
  307. package/dist/schemes/QuestionTool.js +14 -1
  308. package/dist/schemes/QuestionTool.js.map +1 -1
  309. package/dist/schemes/TurnSource.d.ts +3 -2
  310. package/dist/schemes/TurnSource.d.ts.map +1 -1
  311. package/dist/schemes/TurnSource.js +80 -35
  312. package/dist/schemes/TurnSource.js.map +1 -1
  313. package/dist/schemes/Worker.d.ts.map +1 -1
  314. package/dist/schemes/Worker.js +22 -56
  315. package/dist/schemes/Worker.js.map +1 -1
  316. package/dist/schemes/_entry-crud.js +6 -6
  317. package/dist/schemes/_entry-crud.js.map +1 -1
  318. package/dist/schemes/_entry-crud.sql +19 -17
  319. package/dist/schemes/_entry-find.d.ts.map +1 -1
  320. package/dist/schemes/_entry-find.js +6 -5
  321. package/dist/schemes/_entry-find.js.map +1 -1
  322. package/dist/schemes/_entry-fts.d.ts.map +1 -1
  323. package/dist/schemes/_entry-fts.js +6 -3
  324. package/dist/schemes/_entry-fts.js.map +1 -1
  325. package/dist/schemes/_entry-fts.sql +25 -6
  326. package/dist/schemes/_entry-manifest.d.ts +1 -1
  327. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  328. package/dist/schemes/_entry-manifest.js +5 -3
  329. package/dist/schemes/_entry-manifest.js.map +1 -1
  330. package/dist/schemes/_entry-ops.js +4 -4
  331. package/dist/schemes/_entry-ops.js.map +1 -1
  332. package/dist/schemes/_entry-ops.sql +2 -2
  333. package/dist/schemes/_entry-readable.d.ts.map +1 -1
  334. package/dist/schemes/_entry-readable.js +5 -4
  335. package/dist/schemes/_entry-readable.js.map +1 -1
  336. package/dist/schemes/_entry-send.js +2 -2
  337. package/dist/schemes/_entry-send.js.map +1 -1
  338. package/dist/schemes/_search-exclusion.d.ts +1 -0
  339. package/dist/schemes/_search-exclusion.d.ts.map +1 -1
  340. package/dist/schemes/_search-exclusion.js +12 -0
  341. package/dist/schemes/_search-exclusion.js.map +1 -1
  342. package/dist/schemes/_search-index.js +4 -4
  343. package/dist/schemes/_search-index.js.map +1 -1
  344. package/dist/schemes/exec-abort.d.ts.map +1 -1
  345. package/dist/schemes/exec-abort.js +4 -3
  346. package/dist/schemes/exec-abort.js.map +1 -1
  347. package/dist/schemes/exec-lifetime.d.ts +11 -0
  348. package/dist/schemes/exec-lifetime.d.ts.map +1 -0
  349. package/dist/schemes/exec-lifetime.js +29 -0
  350. package/dist/schemes/exec-lifetime.js.map +1 -0
  351. package/dist/server/ClientReads.d.ts.map +1 -1
  352. package/dist/server/ClientReads.js +3 -1
  353. package/dist/server/ClientReads.js.map +1 -1
  354. package/dist/server/Daemon.d.ts +30 -7
  355. package/dist/server/Daemon.d.ts.map +1 -1
  356. package/dist/server/Daemon.js +107 -48
  357. package/dist/server/Daemon.js.map +1 -1
  358. package/dist/server/DaemonModule.d.ts +19 -5
  359. package/dist/server/DaemonModule.d.ts.map +1 -1
  360. package/dist/server/DrainSupervisor.d.ts +13 -11
  361. package/dist/server/DrainSupervisor.d.ts.map +1 -1
  362. package/dist/server/DrainSupervisor.js +87 -98
  363. package/dist/server/DrainSupervisor.js.map +1 -1
  364. package/dist/server/EnvFunctionality.d.ts +12 -3
  365. package/dist/server/EnvFunctionality.d.ts.map +1 -1
  366. package/dist/server/EnvFunctionality.js +19 -14
  367. package/dist/server/EnvFunctionality.js.map +1 -1
  368. package/dist/server/Functionality.d.ts +2 -2
  369. package/dist/server/Functionality.d.ts.map +1 -1
  370. package/dist/server/Functionality.js +97 -62
  371. package/dist/server/Functionality.js.map +1 -1
  372. package/dist/server/FunctionalityManager.d.ts +3 -1
  373. package/dist/server/FunctionalityManager.d.ts.map +1 -1
  374. package/dist/server/FunctionalityManager.js +11 -5
  375. package/dist/server/FunctionalityManager.js.map +1 -1
  376. package/dist/server/HttpListener.d.ts +16 -0
  377. package/dist/server/HttpListener.d.ts.map +1 -0
  378. package/dist/server/HttpListener.js +81 -0
  379. package/dist/server/HttpListener.js.map +1 -0
  380. package/dist/server/MembersFunctionality.d.ts.map +1 -1
  381. package/dist/server/MembersFunctionality.js +12 -16
  382. package/dist/server/MembersFunctionality.js.map +1 -1
  383. package/dist/server/PlurnkSkill.d.ts.map +1 -1
  384. package/dist/server/PlurnkSkill.js +1 -0
  385. package/dist/server/PlurnkSkill.js.map +1 -1
  386. package/dist/server/Retention.d.ts +11 -0
  387. package/dist/server/Retention.d.ts.map +1 -1
  388. package/dist/server/Retention.js +47 -2
  389. package/dist/server/Retention.js.map +1 -1
  390. package/dist/server/Retention.sql +32 -1
  391. package/dist/server/ServiceModules.d.ts.map +1 -1
  392. package/dist/server/ServiceModules.js +2 -0
  393. package/dist/server/ServiceModules.js.map +1 -1
  394. package/dist/server/SkillsFunctionality.d.ts +2 -0
  395. package/dist/server/SkillsFunctionality.d.ts.map +1 -1
  396. package/dist/server/SkillsFunctionality.js +22 -15
  397. package/dist/server/SkillsFunctionality.js.map +1 -1
  398. package/dist/server/WorkspaceCapabilities.d.ts.map +1 -1
  399. package/dist/server/WorkspaceCapabilities.js +1 -0
  400. package/dist/server/WorkspaceCapabilities.js.map +1 -1
  401. package/dist/server/WorkspaceStorage.d.ts +8 -0
  402. package/dist/server/WorkspaceStorage.d.ts.map +1 -0
  403. package/dist/server/WorkspaceStorage.js +26 -0
  404. package/dist/server/WorkspaceStorage.js.map +1 -0
  405. package/dist/server/client-input.d.ts +4 -3
  406. package/dist/server/client-input.d.ts.map +1 -1
  407. package/dist/server/client-input.js +24 -26
  408. package/dist/server/client-input.js.map +1 -1
  409. package/dist/server/dispatch-as-plurnk.js +2 -2
  410. package/dist/server/dispatch-as-plurnk.js.map +1 -1
  411. package/dist/server/drain.sql +69 -132
  412. package/dist/server/envelope.d.ts +2 -2
  413. package/dist/server/envelope.d.ts.map +1 -1
  414. package/dist/server/envelope.js +7 -9
  415. package/dist/server/envelope.js.map +1 -1
  416. package/dist/server/envelope.sql +10 -6
  417. package/dist/server/exec-poll-backoff.js +3 -3
  418. package/dist/server/exec-poll-backoff.js.map +1 -1
  419. package/dist/server/lifecycle-recovery.sql +8 -35
  420. package/dist/server/logEntry.sql +2 -2
  421. package/dist/server/loopDocs.js +3 -3
  422. package/dist/server/loopDocs.sql +4 -2
  423. package/dist/server/model-catalog.d.ts.map +1 -1
  424. package/dist/server/model-catalog.js +2 -2
  425. package/dist/server/model-catalog.js.map +1 -1
  426. package/dist/server/seam-loop.sql +0 -1
  427. package/dist/server/workspace-storage.sql +8 -0
  428. package/dist/service.d.ts.map +1 -1
  429. package/dist/service.js +21 -10
  430. package/dist/service.js.map +1 -1
  431. package/docs/copy-move.md +31 -0
  432. package/docs/env.md +19 -7
  433. package/docs/skills.md +2 -2
  434. package/migrations/002_workers.sql +26 -17
  435. package/migrations/003_loops.sql +82 -28
  436. package/migrations/005_entries.sql +135 -22
  437. package/migrations/006_log.sql +77 -25
  438. package/migrations/007_subscriptions.sql +10 -15
  439. package/package.json +35 -36
  440. package/dist/core/PromptFrames.d.ts +0 -12
  441. package/dist/core/PromptFrames.d.ts.map +0 -1
  442. package/dist/core/PromptFrames.js +0 -28
  443. package/dist/core/PromptFrames.js.map +0 -1
  444. package/dist/schemes/Prompt.d.ts +0 -8
  445. package/dist/schemes/Prompt.d.ts.map +0 -1
  446. package/dist/schemes/Prompt.js +0 -25
  447. package/dist/schemes/Prompt.js.map +0 -1
@@ -12,39 +12,37 @@ CREATE TABLE IF NOT EXISTS loops (
12
12
  sequence INTEGER NOT NULL CHECK (sequence >= 1),
13
13
  status INTEGER NOT NULL DEFAULT 102 CHECK (status IN (100, 102, 200, 202, 413, 429, 499, 500, 504, 508)),
14
14
  prompt TEXT NOT NULL,
15
- -- {§prompt-causal-source}: canonical actor address for the initial prompt;
16
- -- NULL means the owning worker itself.
15
+ -- {§message-causal-source}: canonical actor address for the initial message;
16
+ -- NULL means the owning worker itself. Denormalized headline of the loop's
17
+ -- first message ({§message-arrival}); the inbox row below is the one published.
17
18
  prompt_source TEXT CHECK (prompt_source IS NULL OR length(prompt_source) > 0),
18
- policy TEXT NOT NULL DEFAULT '{"proposals":"review"}' CHECK (json_valid(policy)),
19
+ -- {§loop-policy-composition}: every insert states the complete policy; a column default would
20
+ -- be a second home for a choice the panel owns. Likewise max_turns below.
21
+ policy TEXT NOT NULL CHECK (json_valid(policy)),
19
22
  -- {§worker-model-selection}: immutable loop snapshots of the resolved model route and the
20
23
  -- effective spawn route (was provider_spec/child_provider_spec JSON).
21
24
  model_route_id INTEGER REFERENCES model_routes(id),
22
25
  spawn_model_route_id INTEGER REFERENCES model_routes(id),
23
26
  reasoning_policy TEXT CHECK (reasoning_policy IS NULL OR length(reasoning_policy) > 0),
24
- max_turns INTEGER NOT NULL DEFAULT 50 CHECK (max_turns >= -1),
25
- -- {§worker-scheduled-send}: the selected cadence slot, coalesced at claim.
26
- scheduled_at INTEGER CHECK (scheduled_at IS NULL OR scheduled_at BETWEEN 0 AND 8640000000000000),
27
- repeat_interval_ms INTEGER CHECK (repeat_interval_ms IS NULL OR repeat_interval_ms > 0),
28
- recurrence_root_loop_id INTEGER REFERENCES loops(id),
27
+ max_turns INTEGER NOT NULL CHECK (max_turns >= -1),
29
28
  -- {§loop-execution-allowance}: initialized on first execution, charged with disposition.
30
29
  execution_budget_ms INTEGER CHECK (execution_budget_ms IS NULL OR execution_budget_ms > 0),
31
30
  execution_elapsed_ms REAL NOT NULL DEFAULT 0 CHECK (execution_elapsed_ms >= 0),
32
- -- {§worker-wait-timing}: epoch milliseconds; NULL polling inherits streams.
31
+ -- {§loop-wake-identity}: the wait generation; wait_poll_at below is the next inherited
32
+ -- observation of the worker's open streams ({§exec-lifetime}), epoch milliseconds.
33
33
  wait_revision INTEGER NOT NULL DEFAULT 0 CHECK (wait_revision >= 0),
34
34
  -- {§loop-rail-continuity}: one loop-owned streak and bounded repetition window.
35
35
  strike_streak INTEGER NOT NULL DEFAULT 0 CHECK (strike_streak >= 0),
36
36
  cycle_history TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(cycle_history) AND json_type(cycle_history) = 'array'),
37
37
  cycle_wait_revision INTEGER NOT NULL DEFAULT 0 CHECK (cycle_wait_revision >= 0 AND cycle_wait_revision <= wait_revision),
38
38
  observed_wake_revision INTEGER NOT NULL DEFAULT 0 CHECK (observed_wake_revision >= 0),
39
- wait_deadline_at INTEGER,
40
- wait_poll_interval INTEGER CHECK (wait_poll_interval IS NULL OR wait_poll_interval >= 0),
41
39
  wait_poll_at INTEGER,
42
- -- {§methods-loop-run-open-paths}: the initial prompt frame's selected paths,
43
- -- held here until turn 1 materializes that frame (string[] JSON).
44
- open_paths TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(open_paths)),
45
- -- {§prompt-loop-containment}: one queued recovery loop may carry the
46
- -- complete orphan frame set of one concluded source loop.
40
+ -- {§message-loop-containment}: one queued recovery loop may carry the
41
+ -- complete unpublished message set of one concluded source loop.
47
42
  orphan_source_loop_id INTEGER,
43
+ -- {§loop-claim-latency}: the first time the loop was claimed to run (status 102), stamped by
44
+ -- trigger; its first model turn's start minus this is the wake latency a stall shows up as.
45
+ claimed_at TEXT,
48
46
  -- {§worker-scheme} loop-termination delta: terminated_at is stamped by the trigger
49
47
  -- below when status crosses into terminal (every death-path, uniformly).
50
48
  terminated_at TEXT,
@@ -55,10 +53,6 @@ CREATE TABLE IF NOT EXISTS loops (
55
53
  CONSTRAINT loops_generation_policy_contract CHECK (
56
54
  (model_route_id IS NULL) = (reasoning_policy IS NULL)
57
55
  ),
58
- CONSTRAINT loops_schedule_contract CHECK (
59
- (repeat_interval_ms IS NULL OR scheduled_at IS NOT NULL)
60
- AND (recurrence_root_loop_id IS NULL OR repeat_interval_ms IS NOT NULL)
61
- ),
62
56
  CONSTRAINT loops_terminal_result_contract CHECK (
63
57
  CASE
64
58
  WHEN status IN (100, 102, 202) THEN terminal_result IS NULL
@@ -105,16 +99,75 @@ CREATE UNIQUE INDEX IF NOT EXISTS loops_worker_id_sequence ON loops (worker_id,
105
99
 
106
100
  CREATE UNIQUE INDEX IF NOT EXISTS loops_orphan_source_loop_id ON loops (orphan_source_loop_id);
107
101
 
108
- -- {§db-fk-indexes} Foreign-key check paths (route replacement, recurrence-root cascade) stop scanning loops.
102
+ -- {§db-fk-indexes} Model-route foreign-key checks stop scanning loops.
109
103
  CREATE INDEX IF NOT EXISTS loops_model_route_id ON loops (model_route_id) WHERE model_route_id IS NOT NULL;
110
104
 
111
105
  CREATE INDEX IF NOT EXISTS loops_spawn_model_route_id ON loops (spawn_model_route_id) WHERE spawn_model_route_id IS NOT NULL;
112
106
 
113
- CREATE INDEX IF NOT EXISTS loops_recurrence_root_loop_id ON loops (recurrence_root_loop_id) WHERE recurrence_root_loop_id IS NOT NULL;
107
+ -- {§message-arrival}: the loop's inbox. Every message the loop contains, in arrival order, until
108
+ -- the turn boundary that publishes it as an inbound SEND row in the loop's log; the initial
109
+ -- message is ordinal 1 and doubles as the loop's `prompt` headline. `log_entry_id` is NULL until
110
+ -- publication; a concluded loop's unpublished rows move to its recovery loop
111
+ -- ({§message-loop-containment}).
112
+ CREATE TABLE IF NOT EXISTS loop_messages (
113
+ id INTEGER NOT NULL PRIMARY KEY,
114
+ loop_id INTEGER NOT NULL REFERENCES loops(id) ON DELETE CASCADE,
115
+ ordinal INTEGER NOT NULL CHECK (ordinal >= 1),
116
+ message_key TEXT NOT NULL DEFAULT (lower(hex(randomblob(4)))),
117
+ address TEXT CHECK (address IS NULL OR length(address) > 0),
118
+ -- {§message-causal-source}: NULL means the owning worker itself.
119
+ source TEXT CHECK (source IS NULL OR length(source) > 0),
120
+ body TEXT NOT NULL CHECK (length(body) > 0),
121
+ evidence TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(evidence) AND json_type(evidence) = 'object'),
122
+ -- {§methods-loop-run-open-paths}: the message's selected paths (string[] JSON), read at publication.
123
+ open_paths TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(open_paths)),
124
+ -- The inbound SEND row this message became (log_entries, chapter 006); NULL until published.
125
+ log_entry_id INTEGER,
126
+ UNIQUE (loop_id, ordinal)
127
+ );
128
+ CREATE INDEX IF NOT EXISTS loop_messages_unpublished ON loop_messages (loop_id) WHERE log_entry_id IS NULL;
129
+ CREATE UNIQUE INDEX IF NOT EXISTS loop_messages_key ON loop_messages (message_key);
130
+ CREATE INDEX IF NOT EXISTS loop_messages_address ON loop_messages (address) WHERE address IS NOT NULL;
131
+
132
+ -- {§message-source-scheme}: an address identifies exactly one accepted source in its workspace.
133
+ CREATE TRIGGER IF NOT EXISTS loop_messages_address_unique
134
+ BEFORE INSERT ON loop_messages
135
+ WHEN NEW.address IS NOT NULL AND EXISTS (
136
+ SELECT 1 FROM loop_messages m
137
+ JOIN loops l ON l.id = m.loop_id
138
+ JOIN workers w ON w.id = l.worker_id
139
+ WHERE m.address = NEW.address AND w.workspace_id = (
140
+ SELECT w2.workspace_id FROM loops l2 JOIN workers w2 ON w2.id = l2.worker_id
141
+ WHERE l2.id = NEW.loop_id
142
+ )
143
+ )
144
+ BEGIN
145
+ SELECT RAISE(ABORT, 'message address already accepted in this workspace');
146
+ END;
147
+
148
+ CREATE TRIGGER IF NOT EXISTS loop_messages_immutable_source
149
+ BEFORE UPDATE OF message_key, address, source, body, evidence, open_paths ON loop_messages
150
+ BEGIN
151
+ SELECT RAISE(ABORT, 'accepted message source is immutable');
152
+ END;
153
+
154
+ CREATE TRIGGER IF NOT EXISTS loop_messages_delete_with_history_only
155
+ BEFORE DELETE ON loop_messages
156
+ WHEN EXISTS (SELECT 1 FROM loops WHERE id = OLD.loop_id)
157
+ BEGIN
158
+ SELECT RAISE(ABORT, 'accepted messages can only be removed with their containing history');
159
+ END;
114
160
 
115
- CREATE UNIQUE INDEX IF NOT EXISTS loops_live_recurrence
116
- ON loops (COALESCE(recurrence_root_loop_id, id))
117
- WHERE repeat_interval_ms IS NOT NULL AND status IN (100, 102, 202);
161
+ -- {§message-short-identity}: `key_path` is the model's address for a message — always short, always
162
+ -- `message://<worker>/<key>`, exactly as the worker docs teach. `path` stays the durable identity a
163
+ -- client minted (an AG-UI message UUID, say), which correlation and delivery keep using.
164
+ CREATE VIEW IF NOT EXISTS message_sources AS
165
+ SELECT m.*, w.workspace_id, w.id AS worker_id,
166
+ 'message://' || w.name || '/' || m.message_key AS key_path,
167
+ COALESCE(m.address, 'message://' || w.name || '/' || m.message_key) AS path
168
+ FROM loop_messages m
169
+ JOIN loops l ON l.id = m.loop_id
170
+ JOIN workers w ON w.id = l.worker_id;
118
171
 
119
172
  -- turns
120
173
  -- finish_reason / model: accepted provider-call metadata from the provider
@@ -291,18 +344,19 @@ FROM turns t;
291
344
  -- its curatable log. Derivation attachments are replaceable, source bytes are not.
292
345
  CREATE TABLE IF NOT EXISTS turn_sources (
293
346
  turn_id INTEGER NOT NULL REFERENCES turns(id) ON DELETE CASCADE,
294
- kind TEXT NOT NULL CHECK (kind IN ('ops', 'reasoning')),
347
+ kind TEXT NOT NULL CHECK (kind IN ('ops', 'reasoning', 'note')),
348
+ sequence INTEGER NOT NULL DEFAULT 0 CHECK ((kind = 'note' AND sequence > 0) OR (kind != 'note' AND sequence = 0)),
295
349
  content TEXT NOT NULL,
296
350
  model_call_id INTEGER REFERENCES model_calls(id),
297
351
  deep_hash TEXT REFERENCES derivations(deep_hash),
298
- PRIMARY KEY (turn_id, kind)
352
+ PRIMARY KEY (turn_id, kind, sequence)
299
353
  ) STRICT;
300
354
 
301
355
  -- {§db-fk-indexes} A derivation replacement checks its referrers; the hash is indexed where it is a foreign key.
302
356
  CREATE INDEX IF NOT EXISTS turn_sources_deep_hash ON turn_sources (deep_hash) WHERE deep_hash IS NOT NULL;
303
357
 
304
358
  CREATE TRIGGER IF NOT EXISTS turn_sources_immutable
305
- BEFORE UPDATE OF turn_id, kind, content, model_call_id ON turn_sources
359
+ BEFORE UPDATE OF turn_id, kind, sequence, content, model_call_id ON turn_sources
306
360
  BEGIN
307
361
  SELECT RAISE(ABORT, 'turn source evidence is immutable');
308
362
  END;
@@ -3,6 +3,23 @@
3
3
  -- Version numbers order the chapters on a fresh database; they are not history. A shape
4
4
  -- change edits the chapter in place; existing development databases are recreated.
5
5
 
6
+ -- {§content-store} Every settled body is stored once, addressed by its sha256, however many
7
+ -- channels, workspaces, forks or full-text rows carry it. Rows are immutable; retention collects
8
+ -- what nothing references.
9
+ -- The ONE engine-imposed constraint (SPEC {§stream-constraints}, {§stream-constraints-engine-one-cap}): 100 MiB char-length cap
10
+ -- per content body. All other limits are extrinsic.
11
+ CREATE TABLE IF NOT EXISTS contents (
12
+ id INTEGER NOT NULL PRIMARY KEY,
13
+ hash TEXT NOT NULL UNIQUE CHECK (length(hash) = 64),
14
+ content TEXT NOT NULL CHECK (length(content) <= 104857600)
15
+ ) STRICT;
16
+
17
+ CREATE TRIGGER IF NOT EXISTS contents_immutable
18
+ BEFORE UPDATE ON contents
19
+ BEGIN
20
+ SELECT RAISE(ABORT, 'content is immutable');
21
+ END;
22
+
6
23
  -- derivations
7
24
  -- Content-addressed deep projections. Entry channels and log projections point
8
25
  -- at a COMPLETE artifact by deep_hash; graph and FTS are stored once
@@ -15,6 +32,8 @@ CREATE TABLE IF NOT EXISTS derivations (
15
32
  disposition TEXT CHECK (disposition IN ('indexed', 'excluded', 'unsearchable', 'failed')),
16
33
  reason TEXT,
17
34
  parse_issues INTEGER CHECK (parse_issues IS NULL OR parse_issues > 0),
35
+ -- {§content-store} The text this artifact full-text indexes; NULL = nothing indexed.
36
+ content_id INTEGER REFERENCES contents(id),
18
37
  summary TEXT CHECK (
19
38
  summary IS NULL OR (
20
39
  length(summary) > 0
@@ -37,9 +56,7 @@ CREATE TABLE IF NOT EXISTS entries (
37
56
  authority TEXT NOT NULL DEFAULT '',
38
57
  pathname TEXT NOT NULL,
39
58
  workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
40
- -- Entry-private metadata. Prompt frames use `openPaths` to carry selected
41
- -- workspace paths into the exact turn that publishes the frame
42
- -- ({§methods-loop-run-open-paths}).
59
+ -- Scheme-owned entry metadata.
43
60
  attributes TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attributes)),
44
61
  default_channel TEXT NOT NULL DEFAULT 'body' CHECK (length(default_channel) > 0),
45
62
  output INTEGER NOT NULL DEFAULT 0 CHECK (output IN (0, 1)),
@@ -65,25 +82,20 @@ CREATE TABLE IF NOT EXISTS entries (
65
82
  -- {§entry-owner}, {§execution-output-identity}: one canonical resource key.
66
83
  CREATE UNIQUE INDEX IF NOT EXISTS entries_identity ON entries (workspace_id, scheme, authority, pathname);
67
84
 
68
- -- The ONE engine-imposed constraint (SPEC {§stream-constraints}, {§stream-constraints-engine-one-cap}): 100 MiB char-length cap
69
- -- per channel content body. All other limits are extrinsic.
70
- CREATE TABLE IF NOT EXISTS entry_channels (
85
+ -- entry_channel_rows: the stored shape of a channel. A settled channel points at its body in
86
+ -- `contents`; an active stream's body is a private buffer that is interned when it settles.
87
+ -- Everything reads and writes channels through the `entry_channels` view below.
88
+ CREATE TABLE IF NOT EXISTS entry_channel_rows (
71
89
  entry_id INTEGER NOT NULL,
72
90
  name TEXT NOT NULL CHECK (length(name) > 0),
73
- content TEXT NOT NULL CHECK (length(content) <= 104857600),
91
+ content_id INTEGER REFERENCES contents(id),
92
+ buffer TEXT CHECK (buffer IS NULL OR length(buffer) <= 104857600),
74
93
  mimetype TEXT NOT NULL CHECK (length(mimetype) > 0),
75
94
  weight INTEGER NOT NULL DEFAULT 0 CHECK (weight >= 0),
76
- -- Line count of content, kept by SQLite on every write so a catalog lists extent
77
- -- without reading bodies: a trailing newline terminates the last line; empty
78
- -- content has none ({§tokenomics-weight-stored-at-write}).
79
- lines INTEGER GENERATED ALWAYS AS (
80
- CASE WHEN length(content) = 0 THEN 0
81
- WHEN substr(content, -1) = char(10) THEN length(content) - length(replace(content, char(10), ''))
82
- ELSE length(content) - length(replace(content, char(10), '')) + 1 END
83
- ) STORED,
84
- -- Content identity: sha256 of content, stamped at static writes; streamed
85
- -- appends leave it NULL. Curation weight remains model-independent.
86
- content_hash TEXT,
95
+ -- Line count of the body, kept at every write so a catalog lists extent without reading
96
+ -- bodies: a trailing newline terminates the last line; empty content has none
97
+ -- ({§tokenomics-weight-stored-at-write}).
98
+ lines INTEGER NOT NULL CHECK (lines >= 0),
87
99
  -- Search derivation for this exact addressable channel representation.
88
100
  -- Content or mimetype changes invalidate it at the owning channel row.
89
101
  deep_hash TEXT,
@@ -118,13 +130,92 @@ CREATE TABLE IF NOT EXISTS entry_channels (
118
130
  END
119
131
  END
120
132
  ),
133
+ CHECK ((content_id IS NULL) <> (buffer IS NULL)),
121
134
  PRIMARY KEY (entry_id, name),
122
135
  FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE,
123
136
  FOREIGN KEY (deep_hash) REFERENCES derivations(deep_hash)
124
137
  ) STRICT, WITHOUT ROWID;
125
138
 
126
139
  -- {§db-fk-indexes} Derivation replacement checks channels by hash; catalog joins drive on it too.
127
- CREATE INDEX IF NOT EXISTS entry_channels_deep_hash ON entry_channels (deep_hash) WHERE deep_hash IS NOT NULL;
140
+ CREATE INDEX IF NOT EXISTS entry_channel_rows_deep_hash ON entry_channel_rows (deep_hash) WHERE deep_hash IS NOT NULL;
141
+ -- {§db-fk-indexes} Content collection asks whether any channel still points at a body.
142
+ CREATE INDEX IF NOT EXISTS entry_channel_rows_content ON entry_channel_rows (content_id) WHERE content_id IS NOT NULL;
143
+
144
+ -- {§content-store} The channel as every reader and writer sees it. content_hash is the stored
145
+ -- body's identity (NULL while a stream is active); a writer may bind it, and a bound hash must
146
+ -- be the content's.
147
+ CREATE VIEW IF NOT EXISTS entry_channels AS
148
+ SELECT entry_channel_rows.entry_id, entry_channel_rows.name,
149
+ COALESCE(entry_channel_rows.buffer, contents.content) AS content,
150
+ entry_channel_rows.mimetype, entry_channel_rows.weight, entry_channel_rows.lines,
151
+ contents.hash AS content_hash, entry_channel_rows.deep_hash, entry_channel_rows.state,
152
+ entry_channel_rows.producer_result
153
+ FROM entry_channel_rows
154
+ LEFT JOIN contents ON contents.id = entry_channel_rows.content_id;
155
+
156
+ CREATE TRIGGER IF NOT EXISTS entry_channels_insert
157
+ INSTEAD OF INSERT ON entry_channels
158
+ BEGIN
159
+ SELECT RAISE(ABORT, 'a channel requires content') WHERE NEW.content IS NULL;
160
+ SELECT RAISE(ABORT, 'content_hash does not match content')
161
+ WHERE NEW.content_hash IS NOT NULL AND NEW.content_hash IS NOT sha256(NEW.content);
162
+ INSERT INTO contents (hash, content)
163
+ SELECT COALESCE(NEW.content_hash, sha256(NEW.content)), NEW.content
164
+ WHERE COALESCE(NEW.state, 'static') <> 'active'
165
+ ON CONFLICT (hash) DO NOTHING;
166
+ INSERT INTO entry_channel_rows (entry_id, name, content_id, buffer, mimetype, weight, lines, deep_hash, state, producer_result)
167
+ VALUES (
168
+ NEW.entry_id, NEW.name,
169
+ CASE WHEN COALESCE(NEW.state, 'static') <> 'active'
170
+ THEN (SELECT id FROM contents WHERE hash = COALESCE(NEW.content_hash, sha256(NEW.content))) END,
171
+ CASE WHEN COALESCE(NEW.state, 'static') = 'active' THEN NEW.content END,
172
+ NEW.mimetype, COALESCE(NEW.weight, 0),
173
+ CASE WHEN length(NEW.content) = 0 THEN 0
174
+ WHEN substr(NEW.content, -1) = char(10) THEN length(NEW.content) - length(replace(NEW.content, char(10), ''))
175
+ ELSE length(NEW.content) - length(replace(NEW.content, char(10), '')) + 1 END,
176
+ NEW.deep_hash, COALESCE(NEW.state, 'static'), NEW.producer_result
177
+ );
178
+ END;
179
+
180
+ -- Each column group is written only when it changed, so a search attachment never reads as a
181
+ -- representation write and a lifecycle write never re-stores a body.
182
+ CREATE TRIGGER IF NOT EXISTS entry_channels_update
183
+ INSTEAD OF UPDATE ON entry_channels
184
+ BEGIN
185
+ SELECT RAISE(ABORT, 'a channel is addressed by (entry_id, name)')
186
+ WHERE NEW.entry_id IS NOT OLD.entry_id OR NEW.name IS NOT OLD.name;
187
+ SELECT RAISE(ABORT, 'a channel requires content') WHERE NEW.content IS NULL;
188
+ SELECT RAISE(ABORT, 'content_hash does not match content')
189
+ WHERE NEW.content_hash IS NOT NULL AND NEW.content_hash IS NOT OLD.content_hash
190
+ AND NEW.content_hash IS NOT sha256(NEW.content);
191
+ INSERT INTO contents (hash, content)
192
+ SELECT sha256(NEW.content), NEW.content
193
+ WHERE NEW.state <> 'active' AND (NEW.content IS NOT OLD.content OR OLD.state = 'active')
194
+ ON CONFLICT (hash) DO NOTHING;
195
+ UPDATE entry_channel_rows
196
+ SET content_id = CASE WHEN NEW.state <> 'active'
197
+ THEN (SELECT id FROM contents WHERE hash = sha256(NEW.content)) END,
198
+ buffer = CASE WHEN NEW.state = 'active' THEN NEW.content END,
199
+ lines = CASE WHEN length(NEW.content) = 0 THEN 0
200
+ WHEN substr(NEW.content, -1) = char(10) THEN length(NEW.content) - length(replace(NEW.content, char(10), ''))
201
+ ELSE length(NEW.content) - length(replace(NEW.content, char(10), '')) + 1 END
202
+ WHERE entry_id = OLD.entry_id AND name = OLD.name
203
+ AND (NEW.content IS NOT OLD.content OR (NEW.state = 'active') IS NOT (OLD.state = 'active'));
204
+ UPDATE entry_channel_rows
205
+ SET mimetype = NEW.mimetype, weight = NEW.weight, state = NEW.state, producer_result = NEW.producer_result
206
+ WHERE entry_id = OLD.entry_id AND name = OLD.name
207
+ AND (NEW.mimetype IS NOT OLD.mimetype OR NEW.weight IS NOT OLD.weight
208
+ OR NEW.state IS NOT OLD.state OR NEW.producer_result IS NOT OLD.producer_result);
209
+ UPDATE entry_channel_rows
210
+ SET deep_hash = NEW.deep_hash
211
+ WHERE entry_id = OLD.entry_id AND name = OLD.name AND NEW.deep_hash IS NOT OLD.deep_hash;
212
+ END;
213
+
214
+ CREATE TRIGGER IF NOT EXISTS entry_channels_delete
215
+ INSTEAD OF DELETE ON entry_channels
216
+ BEGIN
217
+ DELETE FROM entry_channel_rows WHERE entry_id = OLD.entry_id AND name = OLD.name;
218
+ END;
128
219
 
129
220
  -- {§crud} A publication is one SQL statement: failure rolls back metadata and
130
221
  -- every channel. The view is an input boundary, not a second persisted copy.
@@ -149,14 +240,28 @@ BEGIN
149
240
  DELETE FROM entry_channels WHERE entry_id = (
150
241
  SELECT id FROM entries WHERE workspace_id = NEW.workspace_id
151
242
  AND scheme = NEW.scheme AND authority = NEW.authority AND pathname = NEW.pathname
152
- );
243
+ ) AND name NOT IN (SELECT key FROM json_each(NEW.channels));
244
+ UPDATE entry_channels
245
+ SET content = json_extract(c.value, '$.content'),
246
+ mimetype = json_extract(c.value, '$.mimetype'),
247
+ weight = json_extract(c.value, '$.weight'),
248
+ content_hash = json_extract(c.value, '$.content_hash'),
249
+ state = json_extract(c.value, '$.state'),
250
+ producer_result = json_extract(c.value, '$.producer_result')
251
+ FROM (SELECT key, value FROM json_each(NEW.channels)) AS c
252
+ WHERE entry_channels.name = c.key
253
+ AND entry_channels.entry_id = (
254
+ SELECT id FROM entries WHERE workspace_id = NEW.workspace_id
255
+ AND scheme = NEW.scheme AND authority = NEW.authority AND pathname = NEW.pathname
256
+ );
153
257
  INSERT INTO entry_channels (entry_id, name, content, mimetype, weight, content_hash, state, producer_result)
154
258
  SELECT e.id, c.key, json_extract(c.value, '$.content'), json_extract(c.value, '$.mimetype'),
155
259
  json_extract(c.value, '$.weight'), json_extract(c.value, '$.content_hash'),
156
260
  json_extract(c.value, '$.state'), json_extract(c.value, '$.producer_result')
157
261
  FROM entries e, json_each(NEW.channels) c
158
262
  WHERE e.workspace_id = NEW.workspace_id AND e.scheme = NEW.scheme
159
- AND e.authority = NEW.authority AND e.pathname = NEW.pathname;
263
+ AND e.authority = NEW.authority AND e.pathname = NEW.pathname
264
+ AND NOT EXISTS (SELECT 1 FROM entry_channel_rows r WHERE r.entry_id = e.id AND r.name = c.key);
160
265
  END;
161
266
 
162
267
  -- symbol_defs
@@ -200,7 +305,15 @@ CREATE INDEX IF NOT EXISTS symbol_refs_source ON symbol_refs (derivation_id, con
200
305
 
201
306
  -- {§find-fulltext-selection} Native full-text index of the addressed READ body.
202
307
  -- rowid is the content-addressed derivation id.
203
- CREATE VIRTUAL TABLE IF NOT EXISTS derivation_fts USING fts5(content);
308
+ -- {§content-store} The index reads its text from the content store instead of keeping a copy:
309
+ -- external content, kept in step by the derivation triggers in _entry-fts.sql.
310
+ CREATE VIEW IF NOT EXISTS derivation_texts AS
311
+ SELECT derivations.id AS id, contents.content AS content
312
+ FROM derivations
313
+ JOIN contents ON contents.id = derivations.content_id;
314
+ CREATE VIRTUAL TABLE IF NOT EXISTS derivation_fts USING fts5(content, content='derivation_texts', content_rowid='id');
315
+ -- {§db-fk-indexes} Content collection asks whether any derivation still indexes a body.
316
+ CREATE INDEX IF NOT EXISTS derivations_content ON derivations (content_id) WHERE content_id IS NOT NULL;
204
317
 
205
318
  -- {§packet-attachment-parts}: READ snapshots survive source changes and log curation.
206
319
  CREATE TABLE IF NOT EXISTS native_contents (
@@ -112,25 +112,73 @@ CREATE INDEX IF NOT EXISTS log_entries_loop_id ON log_entries (l
112
112
  -- {§db-fk-indexes} Derivation replacement checks the rows that cite the hash.
113
113
  CREATE INDEX IF NOT EXISTS log_entries_deep_hash ON log_entries (deep_hash) WHERE deep_hash IS NOT NULL;
114
114
 
115
- -- {§loop-response-messages}: the response is the last delivered message, read from
116
- -- executed evidence so curation cannot retract it. This projection is also used inside
117
- -- atomic cancellation; no second response projection exists.
118
- CREATE VIEW IF NOT EXISTS loop_responses AS
119
- SELECT loop_id, content FROM (
120
- SELECT le.loop_id,
121
- json_extract(le.tx, '$.body.raw') AS content,
122
- ROW_NUMBER() OVER (PARTITION BY le.loop_id ORDER BY t.sequence DESC, le.sequence DESC) AS recency
123
- FROM log_entries le JOIN turns t ON t.id = le.turn_id
124
- WHERE le.op = 'SEND' AND le.state = 'resolved' AND le.status_rx BETWEEN 200 AND 299
115
+ -- {§loop-response-messages}: delivered messages remain executed evidence;
116
+ -- curation and loop termination cannot retract or replace them.
117
+ CREATE VIEW IF NOT EXISTS log_responses AS
118
+ SELECT le.id, le.loop_id, le.turn_id, le.worker_id, le.sequence, le.source, le.origin,
119
+ CASE WHEN json_valid(le.rx) THEN le.rx END AS rx,
120
+ CASE WHEN json_valid(le.tx) THEN COALESCE(json_extract(le.tx, '$.body.raw'), '') END AS content
121
+ FROM log_entries le
122
+ WHERE le.state = 'resolved'
123
+ AND le.op = 'SEND' AND le.status_rx BETWEEN 200 AND 299
125
124
  AND le.source IS NULL AND le.inherited_history = 0
126
125
  AND json_valid(le.tx)
127
- -- {§send-prompt-acceptance}: a SEND to one of this loop's own prompts is the response too;
128
- -- the dispatcher admits only own-loop prompt addresses, so the scheme alone identifies them.
129
- AND (json_type(le.tx, '$.target') = 'null' OR json_extract(le.tx, '$.target.scheme') = 'prompt')
130
- AND json_type(le.tx, '$.body.raw') = 'text'
131
- AND length(json_extract(le.tx, '$.body.raw')) > 0
132
- )
133
- WHERE recency = 1;
126
+ AND json_type(CASE WHEN json_valid(le.rx) THEN le.rx END, '$.answers') = 'array'
127
+ AND typeof(content) = 'text';
128
+
129
+ CREATE VIEW IF NOT EXISTS message_responses AS
130
+ SELECT DISTINCT r.id, m.loop_id, m.worker_id, r.source, r.content, r.rx
131
+ FROM log_responses r
132
+ JOIN workers producer ON producer.id = r.worker_id
133
+ JOIN json_each(r.rx, '$.answers') answer
134
+ JOIN message_sources m ON m.path = answer.value AND m.workspace_id = producer.workspace_id
135
+ UNION ALL
136
+ SELECT r.id, r.loop_id, r.worker_id, r.source, r.content, r.rx
137
+ FROM log_responses r WHERE json_array_length(r.rx, '$.answers') = 0;
138
+
139
+ CREATE VIEW IF NOT EXISTS unanswered_messages AS
140
+ SELECT m.* FROM message_sources m
141
+ WHERE NOT EXISTS (
142
+ SELECT 1 FROM log_responses r
143
+ JOIN workers w ON w.id = r.worker_id, json_each(r.rx, '$.answers') answer
144
+ WHERE w.workspace_id = m.workspace_id AND answer.value = m.path
145
+ );
146
+
147
+ -- {§message-reply-delivery}: notify the sender and the assigned conversation.
148
+ -- UNION prevents duplicate delivery when both roles belong to the same worker.
149
+ -- {§loop-answer}: a child's answer to the very task its parent delegated is NOT delivered here;
150
+ -- the parent receives it once, as the child's termination row, which carries that answer at
151
+ -- ops://<child>/<loop> (operator, 2026-09-19). Replies to any other message still deliver.
152
+ CREATE VIEW IF NOT EXISTS delegated_task_answers AS
153
+ SELECT r.id AS source_record_id, parent.id AS recipient_worker_id
154
+ FROM log_responses r
155
+ JOIN workers producer ON producer.id = r.worker_id
156
+ JOIN workers parent ON parent.id = producer.parent_worker_id
157
+ JOIN json_each(r.rx, '$.answers') answer
158
+ JOIN message_sources m ON m.path = answer.value AND m.workspace_id = producer.workspace_id
159
+ WHERE m.loop_id = r.loop_id AND m.ordinal = 1 AND m.source = 'worker://' || parent.name;
160
+
161
+ CREATE VIEW IF NOT EXISTS message_reply_deliveries AS
162
+ SELECT DISTINCT r.id AS source_record_id, r.loop_id, m.workspace_id,
163
+ r.worker_id AS producer_worker_id, m.worker_id AS recipient_worker_id
164
+ FROM log_responses r
165
+ JOIN workers producer ON producer.id = r.worker_id
166
+ JOIN json_each(r.rx, '$.answers') answer
167
+ JOIN message_sources m ON m.path = answer.value AND m.workspace_id = producer.workspace_id
168
+ UNION
169
+ SELECT r.id, r.loop_id, m.workspace_id, r.worker_id, sender.id
170
+ FROM log_responses r
171
+ JOIN workers producer ON producer.id = r.worker_id
172
+ JOIN json_each(r.rx, '$.answers') answer
173
+ JOIN message_sources m ON m.path = answer.value AND m.workspace_id = producer.workspace_id
174
+ JOIN workers sender ON sender.workspace_id = m.workspace_id AND m.source = 'worker://' || sender.name;
175
+
176
+ CREATE VIEW IF NOT EXISTS delivered_message_replies AS
177
+ SELECT d.* FROM message_reply_deliveries d
178
+ WHERE NOT EXISTS (
179
+ SELECT 1 FROM delegated_task_answers t
180
+ WHERE t.source_record_id = d.source_record_id AND t.recipient_worker_id = d.recipient_worker_id
181
+ );
134
182
 
135
183
  CREATE UNIQUE INDEX IF NOT EXISTS log_entries_model_call_id
136
184
  ON log_entries (model_call_id)
@@ -517,8 +565,12 @@ FROM (
517
565
  -- private to the worker it serves and never crosses to the parent.
518
566
  CASE
519
567
  WHEN t.producer = '_plurnk' AND t.kind IN ('operation', 'initialization', 'maintenance') THEN NULL
568
+ WHEN EXISTS (
569
+ SELECT 1 FROM message_reply_deliveries d
570
+ WHERE d.source_record_id = le.id AND d.recipient_worker_id = w.parent_worker_id
571
+ ) THEN NULL
520
572
  ELSE w.parent_worker_id
521
- END AS target_parent_worker_id,
573
+ END AS recipient_worker_id,
522
574
  CASE
523
575
  WHEN le.state = 'resolved'
524
576
  AND NOT (t.producer = '_plurnk' AND t.kind = 'maintenance')
@@ -567,15 +619,15 @@ FROM (
567
619
  json_remove(le.attrs, '$.__plurnk_curation') AS attrs
568
620
  FROM log_entries le
569
621
  JOIN workers w ON w.id = le.worker_id
570
- JOIN loops l ON l.id = le.loop_id
571
622
  JOIN turns t ON t.id = le.turn_id
572
623
  WHERE le.ambient_event_id IS NULL
573
624
  AND le.inherited_history = 0
574
- AND le.op IS NOT NULL
575
- AND le.state != 'proposed'
576
- AND NOT (
577
- le.op IN ('NEXT', 'WAIT', 'DONE', 'FAIL')
578
- AND l.status IN (200, 413, 429, 499, 500, 504, 508)
625
+ AND COALESCE(json_extract(le.attrs, '$.kind'), '') != 'message'
626
+ AND (
627
+ le.op IN ('EDIT', 'COPY', 'MOVE', 'SEND', 'WORK', 'FORK')
628
+ OR CASE WHEN json_valid(le.tx) THEN json_type(le.tx, '$.runtime') END = 'text'
629
+ OR (le.op = 'KILL' AND COALESCE(le.scheme, 'file') != 'log')
579
630
  )
631
+ AND le.state != 'proposed'
580
632
  ) candidate
581
- WHERE target_parent_worker_id IS NOT NULL OR workspace_broadcast = 1;
633
+ WHERE recipient_worker_id IS NOT NULL OR workspace_broadcast = 1;
@@ -1,5 +1,5 @@
1
1
  -- MIGRATE: 7 subscriptions
2
- -- Chapter 7 of the schema baseline ({§db-schema-baseline}): Subscriptions to streams and their publication cursors.
2
+ -- Chapter 7 of the schema baseline ({§db-schema-baseline}): held streams, events and their observation cursors.
3
3
  -- Version numbers order the chapters on a fresh database; they are not history. A shape
4
4
  -- change edits the chapter in place; existing development databases are recreated.
5
5
 
@@ -19,13 +19,10 @@ CREATE TABLE IF NOT EXISTS subscriptions (
19
19
  published_channel TEXT CHECK (published_channel IS NULL OR length(published_channel) > 0),
20
20
  source TEXT CHECK (source IS NULL OR length(source) > 0),
21
21
  opened_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
22
- -- Execution `<T,P>` poll policy: NULL = default backoff, 0 = disabled, positive = fixed cadence.
23
- -- While the owning loop hibernates (202), an armed policy wakes it to inspect the stream ({§exec-poll}).
24
- poll_seconds INTEGER CHECK (poll_seconds IS NULL OR poll_seconds >= 0),
25
- -- Execution `<0>` — turn-scoped: the stream is reaped at the worker's next pre-turn so it never survives
26
- -- into the subsequent turn; its terminal output surfaces initially visible like any conclusion. {§exec-poll}
22
+ -- `[{"lifetime":"turn"}]`: the stream is reaped at the worker's next pre-turn so it never survives
23
+ -- into the subsequent turn; its terminal output surfaces initially visible like any conclusion. {§exec-lifetime}
27
24
  turn_scoped INTEGER NOT NULL DEFAULT 0 CHECK (turn_scoped IN (0, 1)),
28
- -- {§worker-obligations}: a `<-1>` spawn outlives its loop and is nobody's obligation ({§exec-timeout}).
25
+ -- {§worker-obligations}: a `[{"lifetime":"detached"}]` spawn outlives its loop and is nobody's obligation.
29
26
  detached INTEGER NOT NULL DEFAULT 0 CHECK (detached IN (0, 1)),
30
27
  closed_at TEXT,
31
28
  close_status INTEGER CHECK (close_status IS NULL OR (close_status BETWEEN 100 AND 599)),
@@ -140,14 +137,7 @@ BEGIN
140
137
  SELECT RAISE(ABORT, 'subscription channel result violates the channel producer contract');
141
138
  END;
142
139
 
143
- -- One durable publication cursor per selected subscription channel. Log rows
144
- -- are curated model context and therefore cannot own this lifecycle fact.
145
- -- The row survives KILLing any generated observation and disappears only with
146
- -- its subscription. {§exec-stream}
147
- -- {§worker-obligations}: what a worker still holds — an open stream that is not detached, or a
148
- -- child with an unresolved loop (the same liveness the Delegation section shows, so the 409 gate
149
- -- and the section the model reads never disagree, {§child-orientation}). The one definition the
150
- -- completion gate, the wait matrix, and the drain's wake settlement all read.
140
+ -- {§worker-obligations}: the shared worker work a loop is held on.
151
141
  CREATE VIEW IF NOT EXISTS worker_obligations AS
152
142
  SELECT w.id AS worker_id,
153
143
  EXISTS (
@@ -160,6 +150,11 @@ SELECT w.id AS worker_id,
160
150
  ) AS workers
161
151
  FROM workers w;
162
152
 
153
+ CREATE VIEW IF NOT EXISTS loop_obligations AS
154
+ SELECT l.id AS loop_id, held.streams, held.workers
155
+ FROM loops l JOIN worker_obligations held ON held.worker_id = l.worker_id;
156
+
157
+ -- {§exec-stream}: publication cursors survive curation of generated observations.
163
158
  CREATE TABLE IF NOT EXISTS subscription_publications (
164
159
  id INTEGER NOT NULL PRIMARY KEY,
165
160
  version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),