@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
@@ -1,46 +1,36 @@
1
+ import { PathSyntax, } from "@plurnk/plurnk-contracts";
1
2
  import { LineMarkerOps } from "../content/index.js";
2
3
  import { ReadResolve } from "../content/index.js";
3
4
  import Matcher from "../content/matcher.js";
5
+ import { renderFindContent } from "./_entry-find.js";
4
6
  import { CoreSchemeAdapterBase } from "../core/CoreSchemeServices.js";
7
+ import Results from "../core/results.js";
8
+ import LogBody from "../core/LogBody.js";
9
+ import EntrySemantic from "./_entry-semantic.js";
10
+ import EntryGraph from "./_entry-graph.js";
11
+ import { resolveSearchCandidates } from "./_search-candidate.js";
12
+ import { pathFolderSummaries, pathScope, pathScopeMatches } from "./_path-scope.js";
5
13
  // log:///<loop_seq>/<turn_seq>/<sequence>[/<op>] — the trailing /op segment
6
14
  // is wire-rendering self-documentation derived from the row's `op` field;
7
15
  // parsing accepts it (or omits it) and identifies the row by coordinate. The op
8
16
  // suffix is case-INSENSITIVE: model ops render UPPERCASE (READ/EDIT/FIND) but the
9
- // engine-minted rows are lowercase (`error`, `model`), and those are curatable too —
10
- // a `[A-Z]+`-only suffix silently rejected FOLD(log:///1/6/2/error), so the model
11
- // could not reclaim budget by folding its own error rows and spiralled to 413 (jumbo).
17
+ // engine-minted rows are lowercase (`error`, `model`), and both are curatable.
12
18
  const COORDINATE = /^(\d+)\/(\d+)\/(\d+)(?:\/([A-Za-z]+))?$/;
13
- // §log-coordinate-hierarchy — a log coordinate is a HIERARCHICAL PREFIX: `1` selects loop 1's rows,
19
+ // {§log-coordinate-hierarchy} — a log coordinate is a HIERARCHICAL PREFIX: `1` selects loop 1's rows,
14
20
  // `1/2` turn 1/2's rows, `1/2/3` the one row. A full coordinate is always 3 parts, so a 1- or 2-part
15
21
  // path is unambiguously a prefix — the trailing slash is OPTIONAL (`log:///1/2` ≡ `log:///1/2/`).
16
22
  const PARTIAL_COORDINATE = /^\d+(?:\/\d+)?\/?$/;
17
- // The ONE content projection of a stored rx — what READ shows and therefore what FIND matches
18
- // (§find-source-agnostic: the matcher must see exactly the content the model can retrieve).
19
- // rx.content (with its own mimetype) when the op produced a body; the rx itself as compact JSON
20
- // otherwise (EDIT/SEND acks — inspectable, matchable); the raw string if the rx isn't JSON.
21
- const rxProjection = (rawRx) => {
22
- try {
23
- const rx = JSON.parse(rawRx);
24
- if (typeof rx.content === "string") {
25
- return { content: rx.content, mimetype: typeof rx.mimetype === "string" ? rx.mimetype : "text/plain" };
26
- }
27
- return { content: JSON.stringify(rx), mimetype: "application/json" };
28
- }
29
- catch {
30
- return { content: rawRx, mimetype: "text/plain" };
31
- }
32
- };
33
- // A log target pathname → the coordinate GLOB it scopes (§log-coordinate-hierarchy): a partial
23
+ // A log target pathname → the coordinate GLOB it scopes ({§log-coordinate-hierarchy}): a partial
34
24
  // coordinate (`1`, `1/2`, with or without slash) is a prefix over its descendants; a trailing
35
25
  // slash is the folder idiom; a full coordinate/glob passes through. null = malformed.
36
26
  const coordinateGlob = (pathname) => {
37
27
  if (pathname === "")
38
- return "*";
28
+ return "**";
39
29
  if (pathname.endsWith("/"))
40
- return `${pathname}*`;
30
+ return `${pathname}**`;
41
31
  if (PARTIAL_COORDINATE.test(pathname))
42
- return `${pathname}/*`;
43
- if (parseCoordinate(pathname) !== null || pathname.includes("*"))
32
+ return `${pathname}/**`;
33
+ if (parseCoordinate(pathname) !== null || PathSyntax.hasGlob(pathname))
44
34
  return pathname;
45
35
  return null;
46
36
  };
@@ -54,35 +44,20 @@ const parseCoordinate = (pathname) => {
54
44
  sequence: Number(match[3]),
55
45
  };
56
46
  };
57
- // <L> over a matched row set (mirrors EntryFind.#paginate): <N> picks the Nth,
58
- // <N,M> the range; 0→1, -1→last; out-of-range → 416.
59
- const paginate = (items, marker) => {
60
- const total = items.length;
61
- const { first, last } = marker;
62
- if (last === null) {
63
- if (first === 0 || first === -1)
64
- return { status: 200, items: [] };
65
- if (first > 0 && first <= total)
66
- return { status: 200, items: [items[first - 1]] };
67
- return { status: 416 };
68
- }
69
- const n = first === 0 ? 1 : first;
70
- const m = last === -1 ? total : last;
71
- if (n < 1 || n > total || m < 1 || m > total || n > m)
72
- return { status: 416 };
73
- return { status: 200, items: items.slice(n - 1, m) };
74
- };
47
+ const canonicalCoordinate = (coordinate) => coordinate.replace(/\/[A-Za-z]+$/, "");
48
+ // A rendered log path appends `/OP` to the canonical loop/turn/item coordinate
49
+ // as self-documentation. Selection honors both views: ordinary path globs map
50
+ // the three-level resource tree, while an explicit OP segment can still filter
51
+ // rows (`log:///**/READ`).
52
+ const coordinateScopeMatches = (scope, coordinate) => pathScopeMatches(scope, coordinate) || pathScopeMatches(scope, canonicalCoordinate(coordinate));
75
53
  export default class Log extends CoreSchemeAdapterBase {
76
54
  static manifest = {
77
55
  name: "log",
78
56
  channels: {}, // logs render through read(), not channel storage
79
57
  defaultChannel: "",
80
58
  category: "logging",
81
- scope: "workspace",
82
- // Engine-only WRITES — but KILL ∈ MUTATING_OPS rides this same gate, and log-KILL is the
83
- // model's DB-storage curation lever (plurnk.md:10/:47 + the OP×resource matrix; §model-entry-log-curation).
84
- // The model clears the gate; Log's handler surface (kill only — no edit/writeEntry) is the
85
- // op-level truth, so every other mutating op still 501s.
59
+ // Log KILL is model-authorized curation. Other mutations remain unavailable
60
+ // because Log exposes no edit/writeEntry handler. {§model-entry-log-curation}
86
61
  writableBy: ["plurnk", "model"],
87
62
  volatile: false,
88
63
  modelVisible: true,
@@ -92,106 +67,286 @@ export default class Log extends CoreSchemeAdapterBase {
92
67
  async read(statement, ctx) {
93
68
  const core = this.coreContext(ctx);
94
69
  const { db, workerId } = core;
95
- if (statement.target === null)
96
- return { status: 400, content: null, mimetype: null };
97
- // READ is exact — one coordinate, one row. Tag recall is OPEN[tag]/FIND[tag]'s job (§log-region-tagging),
70
+ const failure = (code, status, detail, extensions = {}) => Results.failure("scheme:log", code, status, detail, { content: null, mimetype: null }, extensions);
71
+ if (statement.target === null) {
72
+ return failure("read-target-required", 400, "READ requires a log coordinate.", {
73
+ recovery: "Provide one exact log coordinate.",
74
+ retryable: false,
75
+ });
76
+ }
77
+ // READ is exact — one coordinate, one row. Tag recall is OPEN[tag]/FIND[tag]'s job ({§log-region-tagging}),
98
78
  // not a filter on a single-row read.
99
79
  if (Array.isArray(statement.signal) && statement.signal.length > 0) {
100
- return { status: 404, content: null, mimetype: null };
80
+ return failure("tagged-coordinate-not-found", 404, "The exact log row does not carry every requested tag.", {
81
+ recovery: "Remove the tag filter or use a log row carrying those tags.",
82
+ retryable: false,
83
+ });
101
84
  }
102
85
  const pathname = (statement.target.kind === "url" ? statement.target.pathname : statement.target.raw).replace(/^\//, "");
103
86
  const coord = parseCoordinate(pathname);
104
- if (coord === null)
105
- return { status: 400, content: null, mimetype: null };
87
+ if (coord === null) {
88
+ return failure("coordinate-malformed", 400, `The log coordinate '${pathname}' is malformed.`, {
89
+ target: pathname,
90
+ recovery: "Use one exact loop/turn/sequence coordinate.",
91
+ retryable: false,
92
+ });
93
+ }
106
94
  const row = await db.log_read_by_coordinate.get({ worker_id: workerId, loop_seq: coord.loopSeq, turn_seq: coord.turnSeq, sequence: coord.sequence });
107
95
  if (row === undefined)
108
- return { status: 404, content: null, mimetype: null };
109
- const { content: underlyingContent, mimetype: underlyingMimetype } = rxProjection(row.rx);
110
- return ReadResolve.resolve({
96
+ return failure("entry-not-found", 404, `No log entry exists at log:///${pathname}.`);
97
+ const { content: underlyingContent, mimetype: underlyingMimetype } = LogBody.resolve({
98
+ op: row.op,
99
+ tx: row.tx,
100
+ rx: row.rx,
101
+ mimetypeTx: row.mimetype_tx,
102
+ mimetypeRx: row.mimetype_rx,
103
+ });
104
+ const resolved = await ReadResolve.resolve({
111
105
  content: underlyingContent,
112
106
  mimetype: underlyingMimetype,
113
107
  lineMarker: statement.lineMarker,
114
108
  body: statement.body,
115
109
  mimetypes: core.mimetypes,
116
110
  });
111
+ if (resolved.status >= 400) {
112
+ if (resolved.problem !== undefined) {
113
+ return Results.assert({
114
+ ...resolved,
115
+ content: null,
116
+ mimetype: null,
117
+ });
118
+ }
119
+ if (resolved.reason === undefined) {
120
+ throw new Error(`Log.read: ReadResolve returned status ${resolved.status} without Problem Details or a diagnostic`);
121
+ }
122
+ return failure(resolved.status === 416
123
+ ? "range-not-satisfiable"
124
+ : resolved.status === 501
125
+ ? "matcher-unavailable"
126
+ : "read-resolution-failed", resolved.status, resolved.reason, {
127
+ ...(resolved.range === undefined ? {} : { range: resolved.range, stage: "projection" }),
128
+ ...(statement.body === null || resolved.status === 416
129
+ ? {}
130
+ : {
131
+ stage: "matcher",
132
+ dialect: statement.body.dialect,
133
+ recovery: resolved.status === 501
134
+ ? "Retry the READ without a content matcher."
135
+ : "Correct or remove the matcher.",
136
+ retryable: false,
137
+ }),
138
+ });
139
+ }
140
+ return { ...resolved };
117
141
  }
118
- // §log-uniform-query — FIND over the worker's log rows, on the SAME source-agnostic primitive
119
- // every entry scheme runs (Matcher.matchCandidates, §find-source-agnostic): candidates are the
120
- // coordinate-scoped rows projected exactly as READ shows them (rxProjection), so every content
121
- // dialect works on log BY CONSTRUCTION and FIND(log)→READ(coordinate) composes like any scheme.
122
- // ~semantic stays 501 until the pump embeds log rows (epic S5); @graph is 501 (log rows carry
123
- // no symbol channels — an honest absence, not an exception).
142
+ // {§log-uniform-query} — FIND over the worker's log rows, on the SAME source-agnostic primitive
143
+ // every entry scheme runs (Matcher.matchCandidates, {§find-source-agnostic}): candidates are the
144
+ // coordinate-scoped rows resolved by LogBody exactly as READ shows them, so every content
145
+ // dialect works on log BY CONSTRUCTION and FIND(log)->READ(coordinate) composes like any scheme.
124
146
  async find(statement, ctx) {
125
- const core = this.coreContext(ctx);
147
+ return this.#find(statement, this.coreContext(ctx), true);
148
+ }
149
+ async #find(statement, core, enforceRenderBudget, allowTargetless = false) {
126
150
  const { db, workerId, mimetypes } = core;
127
- const empty = (status) => ({ status, content: null, mimetype: null, results: [], itemsTokenTotal: 0, pathnames: [], matches: [] });
128
- if (statement.target === null)
129
- return empty(400);
130
- if (statement.body !== null && (statement.body.dialect === "semantic" || statement.body.dialect === "graph"))
131
- return empty(501);
132
- const pathname = (statement.target.kind === "url" ? statement.target.pathname : statement.target.raw).replace(/^\//, "");
151
+ const empty = (status, detail, extensions = {}) => {
152
+ const fields = { content: null, mimetype: null, results: [], itemsTokenTotal: 0, pathnames: [], matches: [] };
153
+ if (status >= 400 && detail === undefined) {
154
+ throw new Error(`Log.find: selection returned status ${status} without Problem Details or a diagnostic`);
155
+ }
156
+ return status >= 400
157
+ ? Results.failure("scheme:log", status === 416 ? "range-not-satisfiable" : status === 501 ? "matcher-not-implemented" : "find-failed", status, detail, fields, extensions)
158
+ : { status, ...fields };
159
+ };
160
+ if (statement.target === null && !allowTargetless) {
161
+ return empty(400, "FIND requires a log target.", {
162
+ recovery: "Provide a log coordinate, prefix, or glob.",
163
+ retryable: false,
164
+ });
165
+ }
166
+ const pathname = statement.target === null
167
+ ? ""
168
+ : (statement.target.kind === "url" ? statement.target.pathname : statement.target.raw).replace(/^\//, "");
133
169
  const glob = coordinateGlob(pathname);
134
- if (glob === null)
135
- return empty(400);
136
- // §log-region-tagging — a tag signal AND-filters the candidates (§find-tag-filter-and-semantics):
170
+ if (glob === null) {
171
+ return empty(400, `The log target '${pathname}' is malformed.`, {
172
+ target: pathname,
173
+ recovery: "Use a log coordinate, prefix, or glob.",
174
+ retryable: false,
175
+ });
176
+ }
177
+ const scope = pathScope(glob, false);
178
+ // {§log-region-tagging} — a tag signal AND-filters the candidates ({§find-tag-filter-and-semantics}):
137
179
  // a row survives only if it carries EVERY listed tag. No signal → the plain coordinate scope.
138
180
  const tags = Array.isArray(statement.signal) ? statement.signal : [];
139
- const rows = tags.length > 0
140
- ? await db.log_find_candidates_tagged.all({ worker_id: workerId, glob, tags: JSON.stringify(tags) })
141
- : await db.log_find_candidates.all({ worker_id: workerId, glob });
181
+ const candidateRows = tags.length > 0
182
+ ? await db.log_find_candidates_tagged.all({ worker_id: workerId, scope_prefix: scope.candidatePrefix, tags: JSON.stringify(tags) })
183
+ : await db.log_find_candidates.all({ worker_id: workerId, scope_prefix: scope.candidatePrefix });
184
+ let rows;
185
+ try {
186
+ rows = candidateRows.filter((row) => coordinateScopeMatches(scope, row.coordinate));
187
+ }
188
+ catch {
189
+ return empty(400, `The log glob '${glob}' is malformed.`, {
190
+ target: glob,
191
+ recovery: "Correct the log glob.",
192
+ retryable: false,
193
+ });
194
+ }
195
+ const candidateByCanonicalCoord = new Map(candidateRows.map((row) => [canonicalCoordinate(row.coordinate), row]));
142
196
  const byCoord = new Map(rows.map((r) => [r.coordinate, r]));
143
- const projected = rows.map((r) => ({ key: r.coordinate, ...rxProjection(r.rx) }));
197
+ const projected = rows.map((r) => ({
198
+ key: r.coordinate,
199
+ ...LogBody.resolve({
200
+ op: r.op,
201
+ tx: r.tx,
202
+ rx: r.rx,
203
+ mimetypeTx: r.mimetype_tx,
204
+ mimetypeRx: r.mimetype_rx,
205
+ }),
206
+ }));
144
207
  let matches;
145
- if (statement.body === null) {
146
- matches = projected.map((c) => ({ pathname: c.key, span: null }));
208
+ if (statement.body?.dialect === "semantic") {
209
+ if (mimetypes === undefined) {
210
+ return empty(501, "Semantic search requires the mimetypes capability.", {
211
+ stage: "semantic-search",
212
+ retryable: false,
213
+ });
214
+ }
215
+ const candidateSet = resolveSearchCandidates(rows.map(({ coordinate, deep_hash }) => ({ key: coordinate, deepHash: deep_hash })));
216
+ if (candidateSet.state === "incomplete")
217
+ return empty(503, `The persistent search index covers ${candidateSet.indexed} of ${candidateSet.total} selected log results.`, {
218
+ search: candidateSet,
219
+ stage: "search-index",
220
+ recovery: "Wait for search indexing to complete before repeating the search.",
221
+ retryable: false,
222
+ });
223
+ const selection = EntrySemantic.resultSelection(statement.lineMarker);
224
+ const ranked = await EntrySemantic.rankCandidates(db, candidateSet.candidates, mimetypes, statement.body.raw, selection);
225
+ if (ranked.status !== 200) {
226
+ return empty(ranked.status, ranked.status === 501
227
+ ? "Similarity-threshold search requires an embedding provider."
228
+ : "The requested similarity threshold is outside the supported range.", {
229
+ stage: "semantic-search",
230
+ ...(selection.threshold === null ? {} : { threshold: selection.threshold }),
231
+ recovery: ranked.status === 501
232
+ ? "Remove the decimal similarity threshold while embeddings are unavailable."
233
+ : "Use a similarity threshold greater than zero and less than one.",
234
+ retryable: false,
235
+ });
236
+ }
237
+ let selected = ranked.results;
238
+ if (selection.page !== null) {
239
+ const page = LineMarkerOps.page(selected, selection.page);
240
+ if (page.status !== 200) {
241
+ if (page.problem === undefined)
242
+ throw new Error("Log semantic FIND pagination failed without Problem Details");
243
+ return Results.assert({
244
+ status: page.status,
245
+ problem: page.problem,
246
+ content: null,
247
+ mimetype: null,
248
+ results: [],
249
+ itemsTokenTotal: 0,
250
+ pathnames: [],
251
+ matches: [],
252
+ });
253
+ }
254
+ selected = page.items ?? [];
255
+ }
256
+ const sourceMatches = selected.map(({ key, lineStart, lineEnd }) => ({
257
+ key,
258
+ span: { lineStart, lineEnd },
259
+ }));
260
+ const readable = Matcher.addTextRegions(sourceMatches, projected);
261
+ matches = readable.map(({ key, matches: ranges }) => ({ pathname: key, matches: ranges }));
262
+ }
263
+ else if (statement.body?.dialect === "graph") {
264
+ const candidateSet = resolveSearchCandidates(rows.map(({ coordinate, deep_hash }) => ({ key: coordinate, deepHash: deep_hash })));
265
+ if (candidateSet.state === "incomplete")
266
+ return empty(503, `The persistent search index covers ${candidateSet.indexed} of ${candidateSet.total} selected log results.`, {
267
+ search: candidateSet,
268
+ stage: "search-index",
269
+ recovery: "Wait for search indexing to complete before repeating the search.",
270
+ retryable: false,
271
+ });
272
+ const universeRows = await db.log_find_candidates.all({ worker_id: workerId, scope_prefix: null });
273
+ const universe = resolveSearchCandidates(universeRows.map(({ coordinate, deep_hash }) => ({ key: coordinate, deepHash: deep_hash })));
274
+ if (universe.state === "incomplete")
275
+ return empty(503, `The persistent search index covers ${universe.indexed} of ${universe.total} log results in the relationship universe.`, {
276
+ search: universe,
277
+ stage: "search-index",
278
+ recovery: "Wait for search indexing to complete before repeating the search.",
279
+ retryable: false,
280
+ });
281
+ const graph = await EntryGraph.matchCandidates(db, universe.candidates, candidateSet.candidates, statement.body.raw);
282
+ if (graph.status !== 200) {
283
+ return empty(graph.status, `The graph matcher '${statement.body.raw}' is malformed.`, {
284
+ stage: "matcher",
285
+ dialect: "graph",
286
+ recovery: "Correct or remove the matcher.",
287
+ retryable: false,
288
+ });
289
+ }
290
+ const sourceMatches = graph.matches.map(({ key, lineStart, lineEnd }) => ({
291
+ key,
292
+ span: { lineStart, lineEnd },
293
+ }));
294
+ const readable = Matcher.addTextRegions(sourceMatches, projected);
295
+ matches = readable.map(({ key, matches: ranges }) => ({ pathname: key, matches: ranges }));
296
+ }
297
+ else if (statement.body === null) {
298
+ matches = projected.map(({ key }) => ({ pathname: key, matches: [] }));
147
299
  }
148
300
  else {
149
- if (mimetypes === undefined)
150
- return empty(501);
301
+ if (mimetypes === undefined) {
302
+ return empty(501, "Content matching requires the mimetypes capability.", {
303
+ stage: "matcher",
304
+ dialect: statement.body.dialect,
305
+ retryable: false,
306
+ });
307
+ }
151
308
  const r = await Matcher.matchCandidates(statement.body, projected, mimetypes);
152
- if (r.status !== 200)
153
- return empty(r.status);
154
- matches = r.matches.map((m) => ({
155
- pathname: m.key,
156
- span: m.span === null ? null : {
157
- ...m.span,
158
- rowStart: m.span.lineStart,
159
- rowEnd: m.span.lineEnd,
160
- },
161
- ...(m.path !== undefined ? { path: m.path } : {}),
162
- }));
309
+ if (r.status !== 200) {
310
+ if (r.problem === undefined) {
311
+ throw new Error(`Log.find: matcher returned status ${r.status} without Problem Details`);
312
+ }
313
+ return Results.assert({
314
+ status: r.status,
315
+ problem: r.problem,
316
+ content: null,
317
+ mimetype: null,
318
+ results: [],
319
+ itemsTokenTotal: 0,
320
+ pathnames: [],
321
+ matches: [],
322
+ });
323
+ }
324
+ matches = r.matches.map(({ key, matches: ranges }) => ({ pathname: key, matches: ranges }));
163
325
  }
164
- if (statement.lineMarker !== null) {
165
- const page = paginate(matches, LineMarkerOps.firstLast(statement.lineMarker));
166
- if (page.status !== 200)
167
- return empty(page.status);
326
+ const folderSummaries = statement.body === null
327
+ ? pathFolderSummaries(scope, candidateRows.map((row) => canonicalCoordinate(row.coordinate)))
328
+ : [];
329
+ if (statement.lineMarker !== null && statement.body?.dialect !== "semantic" && folderSummaries.length === 0) {
330
+ const page = LineMarkerOps.page(matches, statement.lineMarker);
331
+ if (page.status !== 200) {
332
+ if (page.problem === undefined)
333
+ throw new Error("Log FIND pagination failed without Problem Details");
334
+ return Results.assert({
335
+ status: page.status,
336
+ problem: page.problem,
337
+ content: null,
338
+ mimetype: null,
339
+ results: [],
340
+ itemsTokenTotal: 0,
341
+ pathnames: [],
342
+ matches: [],
343
+ });
344
+ }
168
345
  matches = page.items ?? [];
169
346
  }
170
- if (matches.length === 0)
171
- return empty(204);
172
- // §find-count-not-contents is source-agnostic. Log used the shared
173
- // matcher but skipped its cardinality gate, allowing one matcher over a
174
- // large READ projection to retain and later fan out tens of thousands
175
- // of rows. Count-forward here before catalog materialization.
176
- const budget = Number.parseInt(process.env.PLURNK_SERVICE_FIND_MAX_MATCHES ?? "0", 10);
177
- if (budget > 0 && matches.length > budget) {
178
- const unique = new Set(matches.map((m) => m.pathname));
179
- const itemsTokenTotal = [...unique].reduce((sum, pathname) => sum + (byCoord.get(pathname)?.tokens ?? 0), 0);
180
- return {
181
- status: 200,
182
- content: `${matches.length} entries match, exceeding the render budget (${budget}) — not enumerated.`,
183
- mimetype: "text/markdown",
184
- results: [],
185
- itemsTokenTotal,
186
- pathnames: [],
187
- matches: [],
188
- overflow: matches.length,
189
- };
190
- }
191
- // The result rows mirror the catalog-row shape (§find-result-catalog-rows): one item per
192
- // match, keyed by the row's self-documenting path, carrying {mimetype, tokens, lines} so
193
- // the model budgets its READs — uniform with every scheme's FIND.
194
- const results = [];
347
+ // The result rows mirror the catalog-row shape: one item per selected
348
+ // resource, with optional match coordinates for a surgical READ.
349
+ let results = [];
195
350
  const seenPath = [];
196
351
  const seen = new Set();
197
352
  let itemsTokenTotal = 0;
@@ -200,63 +355,123 @@ export default class Log extends CoreSchemeAdapterBase {
200
355
  if (row === undefined)
201
356
  continue;
202
357
  const path = `log:///${m.pathname}`;
203
- const proj = rxProjection(row.rx);
358
+ const proj = LogBody.resolve({
359
+ op: row.op,
360
+ tx: row.tx,
361
+ rx: row.rx,
362
+ mimetypeTx: row.mimetype_tx,
363
+ mimetypeRx: row.mimetype_rx,
364
+ });
204
365
  const item = {
205
366
  path,
206
367
  channels: { [path]: { mimetype: proj.mimetype, tokens: row.tokens, lines: proj.content.length === 0 ? 0 : proj.content.split("\n").length } },
207
368
  };
208
- results.push(m.span !== null ? { ...item, matchSpan: m.span, ...(m.path !== undefined ? { matchPath: m.path } : {}) } : item);
369
+ results.push(m.matches.length > 0 ? { ...item, matches: m.matches } : item);
209
370
  if (!seen.has(m.pathname)) {
210
371
  seen.add(m.pathname);
211
372
  seenPath.push(m.pathname);
212
373
  itemsTokenTotal += row.tokens;
213
374
  }
214
375
  }
376
+ for (const folder of folderSummaries) {
377
+ const members = folder.pathnames.map((coordinate) => candidateByCanonicalCoord.get(coordinate)).filter((row) => row !== undefined);
378
+ const item = {
379
+ path: `log:///${folder.selector}`,
380
+ items: members.length,
381
+ tokens: members.reduce((sum, row) => sum + row.tokens, 0),
382
+ };
383
+ results.push(item);
384
+ itemsTokenTotal += item.tokens;
385
+ }
386
+ if (folderSummaries.length > 0) {
387
+ results.sort((a, b) => a.path.localeCompare(b.path));
388
+ if (statement.lineMarker !== null) {
389
+ const page = LineMarkerOps.page(results, statement.lineMarker);
390
+ if (page.status !== 200) {
391
+ if (page.problem === undefined)
392
+ throw new Error("Log FIND pagination failed without Problem Details");
393
+ return Results.assert({
394
+ status: page.status,
395
+ problem: page.problem,
396
+ content: null,
397
+ mimetype: null,
398
+ results: [],
399
+ itemsTokenTotal: 0,
400
+ pathnames: [],
401
+ matches: [],
402
+ });
403
+ }
404
+ results = page.items ?? [];
405
+ const retained = new Set(results.filter((item) => item.items === undefined).map((item) => item.path.replace(/^log:\/\/\//, "").replace(/^\//, "")));
406
+ matches = matches.filter((match) => retained.has(match.pathname));
407
+ seenPath.splice(0, seenPath.length, ...matches.map((match) => match.pathname).filter((coordinate, i, all) => all.indexOf(coordinate) === i));
408
+ itemsTokenTotal = results.reduce((sum, item) => sum + (item.items === undefined
409
+ ? Object.values(item.channels).reduce((channelSum, channel) => channelSum + channel.tokens, 0)
410
+ : item.tokens ?? 0), 0);
411
+ }
412
+ }
413
+ if (results.length === 0)
414
+ return empty(204);
415
+ // {§find-count-not-contents} is source-agnostic. Count the rendered
416
+ // catalog items; a shallow map's folder summaries replace, rather than
417
+ // conceal, their descendants.
418
+ const budget = Number.parseInt(process.env.PLURNK_SERVICE_FIND_MAX_MATCHES ?? "0", 10);
419
+ if (enforceRenderBudget && budget > 0 && results.length > budget) {
420
+ const noun = results.some((item) => item.items !== undefined) ? "catalog items" : "entries";
421
+ return {
422
+ status: 200,
423
+ content: `${results.length} ${noun} match, exceeding the render budget (${budget}) — not enumerated.`,
424
+ mimetype: "text/markdown",
425
+ results: [],
426
+ itemsTokenTotal,
427
+ pathnames: [],
428
+ matches: [],
429
+ omittedItems: results.length,
430
+ maximumItems: budget,
431
+ };
432
+ }
215
433
  // matches[].pathname is the fan-out's retarget key — `/loop/turn/seq/OP` re-parses as a
216
434
  // coordinate (the /OP suffix is accepted), so READ(log://)<matcher> fan-out delivers rows.
217
435
  const fanMatches = matches.map((m) => ({ ...m, pathname: `/${m.pathname}` }));
218
- return { status: 200, content: JSON.stringify(results), mimetype: "application/json", results, itemsTokenTotal, pathnames: seenPath.map((p) => `/${p}`), matches: fanMatches };
436
+ return { status: 200, content: renderFindContent(results), mimetype: "application/json", results, itemsTokenTotal, pathnames: seenPath.map((p) => `/${p}`), matches: fanMatches };
219
437
  }
220
438
  async open(statement, ctx) {
221
439
  return this.#setExpanded(statement, this.coreContext(ctx), 1);
222
440
  }
223
- // FOLD toggles the expanded bit only — an active subscription stays alive. §subscriptions-fold-keeps-subscription
441
+ // FOLD toggles the expanded bit only — an active subscription stays alive. {§subscriptions-fold-keeps-subscription}
224
442
  async fold(statement, ctx) {
225
443
  return this.#setExpanded(statement, this.coreContext(ctx), 0);
226
444
  }
227
- // Resolve a log:/// target — a concrete coordinate, or a path-glob optionally paginated
228
- // by <L> (OPEN/FOLD only) — to the matched row ids. The ONE resolution OPEN/FOLD and
229
- // KILL share: fold flips `expanded` on the ids, kill deletes them.
230
- async #resolveIds(pathname, lineMarker, ctx) {
445
+ // Resolve a log:/// target — a concrete coordinate or path-glob — to the matched row ids.
446
+ // OPEN/FOLD/KILL share this one path selection; log curation has no positional pagination.
447
+ async #resolveIds(pathname, ctx) {
231
448
  const { db, workerId } = ctx;
232
449
  const coord = parseCoordinate(pathname);
233
- if (coord !== null && lineMarker === null) {
450
+ if (coord !== null) {
234
451
  const row = await db.log_id_by_coordinate.get({ worker_id: workerId, loop_seq: coord.loopSeq, turn_seq: coord.turnSeq, sequence: coord.sequence });
235
452
  return row === undefined ? { status: 404, ids: [] } : { status: 200, ids: [row.id] };
236
453
  }
237
- // §log-coordinate-hierarchy — one resolution for every consumer (curation here, find below).
454
+ // {§log-coordinate-hierarchy} — one resolution for every consumer (curation here, find below).
238
455
  const glob = coordinateGlob(pathname);
239
456
  if (glob === null)
240
- return { status: 400, ids: [], error: `malformed log target '${pathname}' — a coordinate (1/2/3), a prefix (1 or 1/2), or a glob (**/READ)` };
241
- const matched = await db.log_match_coordinates.all({ worker_id: workerId, glob });
242
- // Zero matches on a well-formed glob is a NO-OP SUCCESS, not an error (owner ruling): a
243
- // curation sweep that found nothing to curate steers nothing — 204 keeps it out of the
244
- // errors surface (>= 400), and the rx carries matched: 0, clearly shown.
457
+ return { status: 400, ids: [], error: `The log target '${pathname}' is malformed.` };
458
+ const scope = pathScope(glob, false);
459
+ const candidates = await db.log_match_coordinates.all({ worker_id: workerId, scope_prefix: scope.candidatePrefix });
460
+ let matched;
461
+ try {
462
+ matched = candidates.filter((row) => coordinateScopeMatches(scope, row.coordinate));
463
+ }
464
+ catch {
465
+ return { status: 400, ids: [], error: `The log glob '${glob}' is malformed.` };
466
+ }
467
+ // {§log-curation-folder-idiom} — a well-formed empty selection is a
468
+ // successful no-op and remains outside the error surface.
245
469
  if (matched.length === 0)
246
470
  return { status: 204, ids: [] };
247
- let selected = matched;
248
- if (lineMarker !== null) {
249
- const page = paginate(matched, LineMarkerOps.firstLast(lineMarker));
250
- if (page.status !== 200)
251
- return { status: page.status, ids: [] };
252
- selected = page.items ?? [];
253
- }
254
- if (selected.length === 0)
255
- return { status: 404, ids: [] };
256
- return { status: 200, ids: selected.map((s) => s.id) };
471
+ return { status: 200, ids: matched.map((row) => row.id) };
257
472
  }
258
- // §log-region-tagging — resolve OPEN[tag] to ids: candidates are the target's glob scope (the
259
- // whole run when targetless — a bare OPEN[tag] recalls the entire tagged working-set),
473
+ // {§log-region-tagging} — resolve OPEN[tag] to ids: candidates are the target's glob scope (the
474
+ // whole worker log when targetless — a bare OPEN[tag] recalls the entire tagged working-set),
260
475
  // AND-filtered to rows carrying EVERY listed tag. Zero matches is a no-op success (204), mirroring
261
476
  // #resolveIds — recalling a name that tags nothing steers nothing.
262
477
  async #resolveByTags(statement, tags, ctx) {
@@ -264,86 +479,138 @@ export default class Log extends CoreSchemeAdapterBase {
264
479
  const pathname = statement.target === null ? "" : (statement.target.kind === "url" ? statement.target.pathname : statement.target.raw).replace(/^\//, "");
265
480
  const glob = coordinateGlob(pathname);
266
481
  if (glob === null)
267
- return { status: 400, ids: [], error: `malformed log target '${pathname}' — a coordinate (1/2/3), a prefix (1 or 1/2), or a glob (**/READ)` };
268
- const matched = await db.log_match_coordinates_tagged.all({ worker_id: workerId, glob, tags: JSON.stringify(tags) });
482
+ return { status: 400, ids: [], error: `The log target '${pathname}' is malformed.` };
483
+ const scope = pathScope(glob, false);
484
+ const candidates = await db.log_match_coordinates_tagged.all({
485
+ worker_id: workerId,
486
+ scope_prefix: scope.candidatePrefix,
487
+ tags: JSON.stringify(tags),
488
+ });
489
+ let matched;
490
+ try {
491
+ matched = candidates.filter((row) => coordinateScopeMatches(scope, row.coordinate));
492
+ }
493
+ catch {
494
+ return { status: 400, ids: [], error: `The log glob '${glob}' is malformed.` };
495
+ }
269
496
  if (matched.length === 0)
270
497
  return { status: 204, ids: [] };
271
- let selected = matched;
272
- if (statement.lineMarker !== null) {
273
- const page = paginate(matched, LineMarkerOps.firstLast(statement.lineMarker));
274
- if (page.status !== 200)
275
- return { status: page.status, ids: [] };
276
- selected = page.items ?? [];
498
+ return { status: 200, ids: matched.map((row) => row.id) };
499
+ }
500
+ // A matcher-bearing curation op reuses FIND's complete source-agnostic selector with
501
+ // rendering disabled. OPEN's tags filter candidates; FOLD's tags are withheld until
502
+ // after selection because they apply to the rows being folded.
503
+ async #resolveByMatcher(statement, filterTags, ctx) {
504
+ const selected = await this.#find({
505
+ ...statement,
506
+ op: "FIND",
507
+ signal: filterTags ? statement.signal : null,
508
+ lineMarker: null,
509
+ }, ctx, false, filterTags && Array.isArray(statement.signal) && statement.signal.length > 0 && statement.target === null);
510
+ if (selected.status !== 200)
511
+ return { status: selected.status, ids: [], problem: selected.problem };
512
+ const ids = [];
513
+ for (const { pathname } of selected.matches) {
514
+ const coordinate = parseCoordinate(pathname.replace(/^\//, ""));
515
+ if (coordinate === null)
516
+ throw new Error(`Log matcher selected malformed coordinate '${pathname}'`);
517
+ const row = await ctx.db.log_id_by_coordinate.get({
518
+ worker_id: ctx.workerId,
519
+ loop_seq: coordinate.loopSeq,
520
+ turn_seq: coordinate.turnSeq,
521
+ sequence: coordinate.sequence,
522
+ });
523
+ if (row === undefined)
524
+ return { status: 404, ids: [] };
525
+ ids.push(row.id);
526
+ }
527
+ return ids.length === 0 ? { status: 204, ids: [] } : { status: 200, ids };
528
+ }
529
+ async #applyExpanded(ids, expanded, tags, ctx) {
530
+ for (const id of ids)
531
+ await ctx.db.log_set_expanded_by_id.run({ id, expanded });
532
+ if (expanded === 0) {
533
+ for (const id of ids)
534
+ for (const tag of tags)
535
+ await ctx.db.log_write_tag.run({ log_entry_id: id, tag });
277
536
  }
278
- if (selected.length === 0)
279
- return { status: 404, ids: [] };
280
- return { status: 200, ids: selected.map((s) => s.id) };
537
+ return { status: 200, matched: ids.length };
281
538
  }
282
539
  async #setExpanded(statement, ctx, expanded) {
283
540
  const signal = Array.isArray(statement.signal) ? statement.signal : [];
284
- // §log-region-tagging — OPEN[tag] is the READ side: recall rows by tag, target optional (a bare
541
+ if (statement.body !== null) {
542
+ const matched = await this.#resolveByMatcher(statement, expanded === 1, ctx);
543
+ if (matched.status === 204)
544
+ return { status: 204, matched: 0 };
545
+ if (matched.status !== 200) {
546
+ if (matched.problem !== undefined) {
547
+ return Results.assert({ status: matched.status, problem: matched.problem });
548
+ }
549
+ return Results.failure("scheme:log", matched.status === 404 ? "entry-not-found" : "curation-failed", matched.status, "No log entry matches the requested selection.");
550
+ }
551
+ return this.#applyExpanded(matched.ids, expanded, signal, ctx);
552
+ }
553
+ // {§log-region-tagging} — OPEN[tag] is the READ side: recall rows by tag, target optional (a bare
285
554
  // OPEN[tag] recalls the whole tagged working-set). FOLD never resolves by tag — it is the WRITE
286
555
  // side (it stamps the tag below), always scoped to the target region it folds.
287
556
  if (expanded === 1 && signal.length > 0) {
288
557
  const rt = await this.#resolveByTags(statement, signal, ctx);
289
558
  if (rt.status === 204)
290
559
  return { status: 204, matched: 0 };
291
- if (rt.status !== 200)
292
- return { status: rt.status, ...(rt.error !== undefined ? { error: rt.error } : {}) };
293
- for (const id of rt.ids)
294
- await ctx.db.log_set_expanded_by_id.run({ id, expanded: 1 });
295
- return { status: 200, matched: rt.ids.length };
560
+ if (rt.status !== 200) {
561
+ return Results.failure("scheme:log", "open-failed", rt.status, rt.error ?? "No log entry matches the requested selection.", {}, {
562
+ target: statement.target?.raw ?? null,
563
+ ...(rt.status === 400
564
+ ? {
565
+ recovery: "Use a log coordinate, prefix, or glob.",
566
+ retryable: false,
567
+ }
568
+ : {}),
569
+ });
570
+ }
571
+ return this.#applyExpanded(rt.ids, 1, signal, ctx);
572
+ }
573
+ if (statement.target === null) {
574
+ return Results.failure("scheme:log", "target-required", 400, `${expanded === 1 ? "OPEN" : "FOLD"} requires a log target.`, {}, {
575
+ recovery: "Provide a log coordinate, prefix, or glob.",
576
+ retryable: false,
577
+ });
296
578
  }
297
- if (statement.target === null)
298
- return { status: 400 };
299
579
  const pathname = (statement.target.kind === "url" ? statement.target.pathname : statement.target.raw).replace(/^\//, "");
300
- const r = await this.#resolveIds(pathname, statement.lineMarker, ctx);
580
+ const r = await this.#resolveIds(pathname, ctx);
301
581
  if (r.status === 204)
302
582
  return { status: 204, matched: 0 };
303
- if (r.status !== 200)
304
- return { status: r.status, ...(r.error !== undefined ? { error: r.error } : {}) };
305
- let ids = r.ids;
306
- // §prompt-fold-illegal (#382, owner) — the task frame stays visible: the CURRENT loop's
307
- // foisted preview READ (prompt target, origin plurnk, op READ) refuses FOLD (run43: a weak
308
- // model folded its own task in a housekeeping turn and lost the plot). Every other
309
- // prompt-target row — the born-folded EDIT foist, the model's own deeper prompt READs,
310
- // prior loops' previews — is ordinary curatable memory; KILL still DELETES deliberately.
311
- // A glob sweep silently spares the preview and folds the rest; an explicit fold whose
312
- // whole target IS the preview gets the steer.
313
- if (expanded === 0) {
314
- const previewIds = new Set();
315
- for (const id of r.ids) {
316
- const row = await ctx.db.log_row_target.get({ id });
317
- if (row?.scheme === "prompt" && row.origin === "plurnk" && row.op === "READ" && row.loop_id === ctx.loopId)
318
- previewIds.add(id);
319
- }
320
- if (previewIds.size > 0) {
321
- ids = r.ids.filter((id) => !previewIds.has(id));
322
- if (ids.length === 0)
323
- return { status: 403, error: "Illegal attempt to FOLD the task preview. Use KILL if you want it removed." };
324
- }
583
+ if (r.status !== 200) {
584
+ return Results.failure("scheme:log", r.status === 404 ? "entry-not-found" : "curation-failed", r.status, r.error ?? `No log entry matches '${pathname}'.`, {}, {
585
+ target: pathname,
586
+ ...(r.status === 400
587
+ ? {
588
+ recovery: "Use a log coordinate, prefix, or glob.",
589
+ retryable: false,
590
+ }
591
+ : {}),
592
+ });
325
593
  }
326
- for (const id of ids)
327
- await ctx.db.log_set_expanded_by_id.run({ id, expanded });
328
- // §log-region-tagging — FOLD[tag] is the log's write-op: stamp the tags on the folded rows,
329
- // additively (§edit-tags-additive). Only the rows actually folded are tagged (a preview spared
330
- // above is neither folded nor tagged). OPEN with a signal never reaches here.
331
- if (expanded === 0 && signal.length > 0) {
332
- for (const id of ids)
333
- for (const tag of signal)
334
- await ctx.db.log_write_tag.run({ log_entry_id: id, tag });
335
- }
336
- return { status: 200, matched: ids.length };
594
+ return this.#applyExpanded(r.ids, expanded, signal, ctx);
337
595
  }
338
- // KILL erases log items (plurnk.md:36, :98) — the model's DB-storage curation lever and
339
- // the only way to shed accumulated log rows in a long workspace (FOLD only collapses the
340
- // render; the row persists). Same resolution as OPEN/FOLD, DELETE instead of flip. KILL
341
- // carries no <L> result slot, so no pagination — a concrete coordinate or a path-glob.
596
+ // KILL shares OPEN/FOLD's address resolution, deletes instead of flipping visibility,
597
+ // and carries no positional scope. {§model-entry-log-curation} {§log-curation-set-selection}
342
598
  async kill(pathname, _signal, ctx) {
343
599
  const core = this.coreContext(ctx);
344
- const r = await this.#resolveIds(pathname.replace(/^\//, ""), null, core);
345
- if (r.status !== 200)
346
- return { status: r.status };
600
+ const r = await this.#resolveIds(pathname.replace(/^\//, ""), core);
601
+ if (r.status === 204)
602
+ return { status: 204 };
603
+ if (r.status !== 200) {
604
+ return Results.failure("scheme:log", r.status === 404 ? "entry-not-found" : "kill-failed", r.status, r.error ?? `No log entry matches '${pathname}'.`, {}, {
605
+ target: pathname,
606
+ ...(r.status === 400
607
+ ? {
608
+ recovery: "Use a log coordinate, prefix, or glob.",
609
+ retryable: false,
610
+ }
611
+ : {}),
612
+ });
613
+ }
347
614
  for (const id of r.ids)
348
615
  await core.db.log_delete_by_id.run({ id });
349
616
  return { status: 200 };