@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
package/SPEC.md CHANGED
@@ -4,35 +4,35 @@ Canonical contracts plurnk-service exposes, architecture it implements, promises
4
4
 
5
5
  ## Contents
6
6
 
7
- - [Glossary](#glossary-glossary)
7
+ - [Glossary](#glossary)
8
8
  - [Architecture](#arch-architecture)
9
9
  - [Workers and workspace boundaries](#actor-boundary-workers-and-workspace-boundaries)
10
10
  - [File membership and project roots](#membership-file-membership-and-project-roots)
11
11
  - [Loop scheduling and lifecycle](#worker-loop-lifecycle-loop-scheduling-and-lifecycle)
12
- - [Provider Contract](#provider-provider-contract)
12
+ - [Provider Contract](#provider-contract)
13
13
  - [Scheme Contract](#scheme-scheme-contract)
14
14
  - [Mimetype Contract](#mimetype-mimetype-contract)
15
15
  - [Search indexing](#persistent-search-index-search-indexing)
16
16
  - [Channel Topology](#channels-channel-topology)
17
- - [Op Surface](#op-op-surface)
17
+ - [Op Surface](#op-surface)
18
18
  - [Proposals and client interactions](#proposal-proposals-and-client-interactions)
19
19
  - [Stream Model](#stream-stream-model)
20
- - [Storage Model](#storage-storage-model)
20
+ - [Storage Model](#storage-model)
21
21
  - [Plugin composition](#core-plugin-composition-plugin-composition)
22
22
  - [Bundled Set](#bundled-set-bundled-set)
23
- - [Grammar Dependency](#grammar-grammar-dependency)
23
+ - [Grammar Dependency](#grammar-dependency)
24
24
  - [Operator Configuration](#operator-config-operator-configuration)
25
25
  - [Module seam](#rpc-module-seam)
26
- - [Workspace Functionality](#functionality-workspace-functionality)
26
+ - [Workspace Functionality](#workspace-functionality)
27
27
  - [Application interface](#methods-application-interface)
28
28
  - [Packet assembly](#packet-assembly-packet-assembly)
29
29
  - [Packet shape](#packet-packet-shape)
30
- - [Matcher selection and text regions](#matcher-matcher-selection-and-text-regions)
31
- - [Testing and evidence](#test-taxonomy-testing-and-evidence)
30
+ - [Matcher selection and text regions](#matcher-selection-and-text-regions)
31
+ - [Testing and evidence](#testing-and-evidence)
32
32
 
33
33
  ---
34
34
 
35
- ## §glossary Glossary
35
+ ## Glossary
36
36
 
37
37
  Canonical meanings. When a doc, comment, test name, or commit message uses one of these words, it means exactly what's written here. Drift is a bug.
38
38
 
@@ -66,28 +66,28 @@ flowchart LR
66
66
  | **`--run`** | Client compatibility | A compatibility-sensitive client spelling, not an internal entity. |
67
67
  | **session** | Retired/unqualified | Not a PLURNK lifecycle noun. Use the actual core noun; a third-party standard may use only its explicitly qualified protocol term. <!-- lexicon-allow: this row defines the retired noun --> |
68
68
 
69
- ### §storage-terms Storage terms
69
+ ### Storage terms
70
70
 
71
71
  | Term | Meaning |
72
72
  |---|---|
73
73
  | **entry** | The unit of canonical state. Identity: `(workspace_id, scheme, authority, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus scheme-private `attributes`. |
74
74
  | **channel** | A named content buffer on an entry. Examples: `body`, `stdout`, `stderr`, `headers`, `symbols`. Each channel has `content`, `mimetype`, curation `weight`, and lifecycle `state`. |
75
- | **scheme** | An addressed capability family + handler. Built-ins include `worker`, `prompt`, `log`, and bare/file paths; discovered schemes and executor-runtime tags extend that set. Internal `exec` routes executions but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
76
- | **mimetype** | A channel's content type. Drives the handler that produces the structural projections (`symbols`, `deepJson`, `deepXml`). Consumption surface {§mimetype-surface}; author contract: [plurnk-mimetypes](../plurnk-mimetypes/SPEC.md). |
77
- | **provider** | An LLM transport implementing the `@plurnk/plurnk-providers` `Provider` interface. Core supplies an assembled request and generation context; the provider owns endpoint adaptation and normalized response evidence. Consumption surface {§provider}; author contract: [plurnk-providers](../plurnk-providers/SPEC.md). |
75
+ | **scheme** | An addressed capability family + handler. Built-ins include `worker`, `log`, `ops`, `reasoning`, and bare/file paths; discovered schemes and executor-runtime tags extend that set. Internal `exec` routes executions but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
76
+ | **mimetype** | A channel's content type. Drives the handler that produces the structural projections (`symbols`, `deepJson`, `deepXml`). Consumption surface {§mimetype}; author contract: [plurnk-mimetypes](../plurnk-mimetypes/SPEC.md). |
77
+ | **provider** | An LLM transport implementing the `@plurnk/plurnk-providers` `Provider` interface. Core supplies an assembled request and generation context; the provider owns endpoint adaptation and normalized response evidence. Consumption surface {§provider-surface}; author contract: [plurnk-providers](../plurnk-providers/SPEC.md). |
78
78
 
79
- ### §state-terms State / status
79
+ ### State / status
80
80
 
81
81
  Independent axes on entries and channels. Confusion across them is a recurring source of bugs.
82
82
 
83
83
  | Term | Type | Meaning |
84
84
  |---|---|---|
85
- | **status** | HTTP int | Outcome of an operation. Carried on `log_entries.status_rx`, returned from op handlers. Per the catalogue ({§send-dispatch}). |
85
+ | **status** | HTTP int | Outcome of an operation. Carried on `log_entries.status_rx`, returned from op handlers. Per the catalogue ({§operation-results}). |
86
86
  | **channel state** | `static \| active \| closed \| errored` | Streaming lifecycle of a channel's content. Metadata, not gating — engine renders content regardless of state. |
87
87
  | **proposal state** | `proposed \| resolved \| failed \| cancelled` | Proposal lifecycle (`log_entries.state`) under {§proposal}; distinct from entry identity and channel state. |
88
88
  | **outcome** | `string \| null` | Short reason for `failed`/`cancelled` (`"permission:403"`, `"aborted"`, `"not_found"`). Opaque to most callers. |
89
89
 
90
- ### §authority-terms Writer / authority
90
+ ### Writer / authority
91
91
 
92
92
  | Term | Meaning |
93
93
  |---|---|
@@ -95,7 +95,7 @@ Independent axes on entries and channels. Confusion across them is a recurring s
95
95
  | **origin** | Synonym for writer in log_entries (`log_entries.origin`). Historical naming; treat as equivalent. |
96
96
  | **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, _plurnk, plugin}`. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry ({§subscriptions} action-entry-as-outcome). |
97
97
 
98
- ### §execution-terms Execution terms
98
+ ### Execution terms
99
99
 
100
100
  | Term | Meaning |
101
101
  |------------------------------|---|
@@ -124,17 +124,11 @@ Independent axes on entries and channels. Confusion across them is a recurring s
124
124
  Daemon composition and startup. Worker attention and workspace state follow
125
125
  {§actor-boundary} and {§machine-processes}.
126
126
 
127
- ### §ecosystem Ecosystem
127
+ ### Ecosystem
128
128
 
129
129
  The root [`ARCHITECTURE.md`](../ARCHITECTURE.md) owns the platform process and
130
130
  package map. The default installed composition is specified in {§bundled-set}.
131
131
 
132
- §ecosystem-composed-host Core is the composed runtime: it owns persistence,
133
- scheduling, packet assembly, dispatch, and cross-capability orchestration while
134
- consuming the language and each capability family's author contract. Domain
135
- logic stays with its owning package. AG-UI projects that runtime to clients;
136
- clients render and submit actions but contain no engine logic.
137
-
138
132
  ### §observability-boundary Observability boundary
139
133
 
140
134
  OpenTelemetry may observe PLURNK; it never becomes product state, failure transport, scheduler input, model teaching, or client protocol. Domain and client activity remain on AG-UI. Reusable packages depend on the OTel API only; the daemon constructs only the explicitly configured trace and metric providers. An unconfigured or standards-valid disabled process loads no SDK or exporter implementation and keeps the API's no-op behavior with bounded overhead. OTel Logs have no provider or initialization path.
@@ -142,11 +136,15 @@ OpenTelemetry may observe PLURNK; it never becomes product state, failure transp
142
136
  Configuration uses the standard `OTEL_*` environment: `OTEL_TRACES_EXPORTER` / `OTEL_METRICS_EXPORTER` select `otlp` or `console` per signal (a missing or `none` value keeps that signal off; no SDK default selects an exporter), `OTEL_SERVICE_NAME` names the service (default `plurnk-service`), case-insensitive `true` in `OTEL_SDK_DISABLED` turns the boundary off, and OTLP exporters honor `OTEL_EXPORTER_OTLP_*`. An unknown exporter name fails daemon boot; a typo never silently disables observation. OTel Logs and direct draft semantic-convention use are excluded. HTTP spans carry only an AG-UI-owned bounded route class, never an input pathname or query. Spans otherwise carry high-cardinality identifiers; metric labels stay low-cardinality. Prompts, reasoning, file bodies, arbitrary URLs, secrets, and plugin payloads are never recorded as attributes or metric values by default. Exporter failure cannot change product results or client lifecycle. Daemon, telemetry, and database teardown are independent reverse-ownership phases; every phase runs and aggregate failure preserves every cause.
143
137
 
144
138
  §observability-genai-conventions **GenAI convention projection.** Provider
145
- request spans use the OpenTelemetry GenAI semantic conventions: a
146
- CLIENT-kind `gen_ai.client.request` span carrying `gen_ai.operation.name`
147
- (`chat`), `gen_ai.system` (the provider alias), and `gen_ai.request.model`;
139
+ request spans follow the [GenAI registry at `c88d504`](https://github.com/open-telemetry/semantic-conventions-genai/tree/c88d504ab3d9879f8e50d3cc87e69775e11db234),
140
+ which depends on core semantic conventions v1.44.0: a CLIENT-kind
141
+ `chat {model}` span carrying `gen_ai.operation.name` (`chat`),
142
+ `gen_ai.provider.name` (the constructed route's provider ID in the registry's
143
+ spelling, never its tuning alias; unmatched IDs are preserved, `other` for an
144
+ unregistered handle), and `gen_ai.request.model`;
148
145
  on settlement it gains `gen_ai.usage.input_tokens` and
149
- `gen_ai.usage.output_tokens` from validated accounting plus
146
+ `gen_ai.usage.output_tokens` by aggregating every reported request quantity in
147
+ validated accounting ({§tokenomics-provider-usage}), plus
150
148
  `gen_ai.response.finish_reasons`; failures carry `error.type` as the class
151
149
  name only. Plurnk custom attributes (attempt, kind, status, loop/turn ids)
152
150
  ride alongside and never replace the convention attributes. The redaction
@@ -154,59 +152,34 @@ boundary is unchanged — no prompts, reasoning, bodies, or URLs. This is the
154
152
  sanctioned exception to the blanket draft-convention exclusion; no other
155
153
  draft convention is projected.
156
154
 
157
- ### §standards-discernment Standards discernment
158
-
159
- Seven principles govern which exterior standards Plurnk conforms to (#299):
160
-
161
- 1. **UVP first.** Never conform away what users chose Plurnk for; the OP grammar, curated log, packet, and worker graph are the product, not a compatibility gap.
162
- 2. **Right-fit.** Hobbyist-first: an enterprise-grade feature is acceptable only when its cost lands on the party that wants it, never on general adoption.
163
- 3. **Traction.** Count running counterparties today; integration horizon must be shorter than the standard's expected half-life. Sockets stay configurable with no default until a candidate earns it.
164
- 4. **POSIX app identity.** Decades-stable host-ecosystem conventions (XDG, NO_COLOR, man, completions, service units) outrank months-stable AI-pipeline fashions.
165
- 5. **Faces, never organs.** A standard adopts as one adapter or projection behind an existing seam; if it cannot, that is the alarm, and it goes to a design gate.
166
- 6. **Deletion is the price of admission.** A standard earns adoption by deleting bespoke surface (the ACP Plan object deleted the Markdown plan microformat); parallel representations, second discovery paths, and compatibility grammars are refused.
167
- 7. **Two arbiters.** Model-facing surfaces change only on measured model evidence; human-facing surfaces follow host-ecosystem convention without ceremony. Standards bodies get a vote on neither.
168
-
169
- ### §in-process In-process architecture
170
-
171
- Composed daemon internals + admin CLI. Four plug points:
172
-
173
- - **Providers** ({§provider}) — LLM transports. Engine sends a turn's messages, receives raw content + usage; engine parses the content into `PlurnkStatement[]`.
174
- - **Schemes** ({§scheme}) — addressed capabilities. A scheme handler interprets targets under its prefix and owns its storage substrate.
175
- - **Mimetypes** ({§mimetype}) — content interpretation. Render-time handlers consume channel content; framework owns the dispatch.
176
- - **Executors** ({§exec} / {§bundled-set}) — execution dispatch for subprocess, data, and pure-computation runtimes; web discovery rides the ordinary MCP surface.
177
-
178
- Core's internal owners compose without becoming new package or public seams:
179
-
180
- | Owner | Machine |
181
- |-------|---------|
182
- | `Daemon` | Process/module lifecycle, dependency composition, provider policy, notifications, and the external client façade. |
183
- | `DrainSupervisor` | One worker's queue consumer, drain identity, wake obligations, cancellation scope, poll/park timers, and terminal cleanup. |
184
- | `Engine` | Loop lifecycle and the public turn, dispatch, derivation, and proposal façades. |
185
- | `TurnRunner` | Model inference and `_plurnk` initialization, from materialization and output admission through operation settlement. |
186
- | `Dispatcher` | Operation admission/routing, scheme execution, proposal waiting, curation, and durable log writes. |
187
- | `ResourceMutations` | EDIT/COPY/MOVE selection, anchor preconditions, cross-scheme effects, and mutation settlement. |
188
-
189
- Capability-specific behavior remains with the owning plug point.
155
+ ### In-process architecture
190
156
 
191
- The contracts package (`@plurnk/plurnk-contracts`) owns the parser and AST contract. Schemes receive parsed statement fragments via dispatch.
192
-
193
- Server posture: this package is the one long-running runtime process. `plurnk-agui` exposes its external protocol; user-facing clients run separately and do not call core's in-process seam directly.
157
+ The process and package map is ARCHITECTURE.md's; this package's AGENTS.md maps core's internal
158
+ owners. Capability-specific behavior remains with the owning plug point.
194
159
 
195
160
  §service-worker-composition The service launcher and the live/demo workspace
196
- helper share one registration of default worker-facing modules: MCP and outbound
197
- A2A. Their management families and readable reference documents are present even
198
- with no enabled attachments. Workspace capability policy controls every actor's
199
- surface; registering a family does not enable a remote attachment. Client and
161
+ helper share one registration of default worker-facing modules: MCP, outbound
162
+ A2A, and Schedule. Their management families and readable reference documents are
163
+ present even with no enabled definitions. Workspace capability policy controls every actor's
164
+ surface; registering a family does not enable its definitions. The real-model
165
+ profile ({§operator-config-real-model-profile}) leaves ambient MCP attachments and
166
+ service schedules disabled by default; specimens may add their own through the
167
+ ordinary management surface. Client and
200
168
  inbound-A2A listeners and host hooks remain launcher-owned.
201
169
 
202
170
  ### §service-package-exports Package export surface
203
171
 
204
172
  | Export path | Current contract |
205
173
  |---------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
206
- | `@plurnk/plurnk-service` | Frozen 1.x compatibility barrel. It retains the previously published runtime and type surface, gains no new APIs, and is not the client boundary. Removal is SemVer-major. |
174
+ | `@plurnk/plurnk-service` | Frozen 1.x compatibility barrel of the exports below. It gains no new APIs and is not the client boundary. Removal is SemVer-major. |
207
175
  | `@plurnk/plurnk-service/digest` | Supported programmatic forensic surface owned by {§digest-programmatic-surface}. |
208
176
  | `@plurnk/plurnk-service/package.json` | Supported package metadata surface. |
209
177
 
178
+ | Root exports | Names |
179
+ |--------------|-------|
180
+ | Runtime | `Daemon`, `Engine`, `EnvFlags`, `Exec`, `File`, `Log`, `Mimetypes`, `Mock`, `Paths`, `SchemeRegistry`, `Skill` |
181
+ | Types | `ChatMessage`, `EditResult`, `FlagDescriptor`, `MockAssistant`, `MockResponse`, `OpenFoldResult`, `ReadResult` |
182
+
210
183
  New clients use AG-UI. A new library contract belongs in its owning package or
211
184
  an explicitly specified subpath, not in the frozen root barrel.
212
185
 
@@ -224,13 +197,27 @@ flowchart LR
224
197
  DAEMON -. failure .-> TEARDOWN["Close every started owner"] --> FAIL
225
198
  ```
226
199
 
227
- §startup-listener-admission The production service binds its sole client
228
- listener before creating, opening, replacing, rotating, migrating, or otherwise
229
- mutating anything in the durable data directory. A process that loses the
230
- listener race fails with the originating address error and byte-identical
231
- durable storage. The client-interface module owns the socket continuously; it
232
- answers 503 until activated, so early ownership introduces neither traffic nor a
233
- close/rebind race.
200
+ §startup-listener-admission The production service binds its one listener
201
+ ({§http-host}) before creating, opening, replacing, rotating, migrating, or
202
+ otherwise mutating anything in the durable data directory. A process that loses
203
+ the listener race fails with the originating address error and byte-identical
204
+ durable storage. Core owns the socket continuously; it answers 503 until the
205
+ client-interface module mounts the root at daemon activation, so early
206
+ ownership introduces neither traffic nor a close/rebind race.
207
+
208
+ §http-host **The daemon opens exactly one transport.** Core binds the HTTP
209
+ listener on `PLURNK_HOST:PLURNK_PORT` and offers it to every exterior adapter as
210
+ `registerHttpRoute(prefix, handler)` and `httpAddress()` on the application port
211
+ ({§application-port}). A prefix is an absolute pathname. Each request goes to the
212
+ longest mounted prefix; a prefix claims itself and the subtree beneath it, never
213
+ a longer sibling name; `/` is the root and receives whatever nothing more
214
+ specific claimed. Until a root is mounted the listener answers `503
215
+ service-starting` to every request: the service has not admitted its client
216
+ interface. Adapters mount at `start()`, after durable lifecycle recovery, and
217
+ none opens a socket of its own under the daemon — a module hosted *without* a
218
+ daemon may bind a private one, which is outside this contract. The standards
219
+ address by URL, never by port (#641): AG-UI mounts `/` and `/agui`, A2A the
220
+ well-known card and its endpoint path, on the same address.
234
221
 
235
222
  §startup-admission-order After listener ownership, database admission completes
236
223
  before provider or capability initialization can perform external work. Every
@@ -254,7 +241,7 @@ shared workspace state ({§packet}, {§membership}). Other journals are not
254
241
  automatically injected. This follows "one packet, one worker," not an access
255
242
  filter over workspace resources.
256
243
 
257
- §actor-boundary-origin-not-filter `origin` ({§authority-terms}) is
244
+ §actor-boundary-origin-not-filter `origin` (the writer, {§scheme-surface-writableby-403}) is
258
245
  **attribution** — the delta's provenance ({§env-delta}) — and is never read to
259
246
  filter a row.
260
247
 
@@ -273,13 +260,14 @@ file or entry through its ordinary read-authority boundary ({§worker-read-scope
273
260
  | Door | Carries | Wake behavior |
274
261
  | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
275
262
  | Environment | A direct child's durable activity to its parent, plus a successful mutation of the deliberately global `worker:///` commons to every worker. | Intermediate activity and commons never wake; a child's terminal disposition wakes its parent. |
276
- | Voice | A directed `loop.inject` or ```` ```SEND (worker://name) ```` message. | An active worker folds it into its next turn; an idle one wakes. |
263
+ | Voice | A directed `loop.inject` or ```` ```SEND (worker://name) ```` request, or an exact-message reply ({§message-reply-delivery}). | Requests enter the next packet or start queued work; replies wake existing assigned/native-sender work without creating a request. |
277
264
 
278
265
  §actor-boundary-lineage-attention **Addressability is workspace-wide; attention
279
266
  is lineage-scoped.** Project files, registered resources, and named scratch
280
267
  entries remain addressable throughout the workspace, but ordinary changes do
281
- not enter unrelated workers' logs. A child's activity reaches only its direct
282
- parent. That observer row carries the source occurrence identity and never
268
+ not enter unrelated workers' logs. Eligible child actions ({§env-delta-child-activity})
269
+ reach only the direct parent; exploration and local curation do not. That
270
+ observer row carries the source occurrence identity and never
283
271
  republishes, so grandparents observe what their own direct children do without
284
272
  receiving an automatic recursive mirror of every descendant.
285
273
 
@@ -317,8 +305,10 @@ Plurnk never stages a file or runs `git add`.
317
305
 
318
306
  §turn0-agents-stunt **The project AGENTS.md is a turn-0 stunt.** When
319
307
  `<projectRoot>/AGENTS.md` exists, LoopDocs materializes it as the workspace's shared
320
- `worker:///_plurnk/agents.md` entry and the engine foists one READ of it into
321
- that model worker's first turn — visible, logged, line-addressable. Absent
308
+ `worker:///_plurnk/AGENTS.md` entry and the engine foists one READ of it into
309
+ that model worker's first turn — visible, logged, line-addressable. The entry
310
+ keeps the standard's own name, as a nested instruction file does: that name is
311
+ in the model's prior, and no other generated document is called it. Absent
322
312
  file: no entry, no stunt, nothing 404s. The global XDG configuration `AGENTS.md`
323
313
  remains system-prompt policy ({§policy-sections}); the stunt carries only
324
314
  local repo guidance.
@@ -338,11 +328,11 @@ narrow or omit the reference catalogs under {§capability-admission}.
338
328
  | Agent Skills | `skill://*/SKILL.md` | `<1,-1>`; {§skills-resources} |
339
329
  | Plurnk references: executors, schemes, family managers | `worker:///_plurnk/plurnk/*.md` | `<1,-1>` |
340
330
  | Enabled tools | `worker:///_plurnk/tools/*.md` | `<1,-1>`; configured expansions follow under {§tools-resource-materialization} |
341
- | Enabled agents | `worker:///_plurnk/agents/*.md` | `<1,-1>`; {§a2a-agents-catalog} |
331
+ | Enabled agents | `worker:///_plurnk/a2a/*.md` | `<1,-1>`; {§a2a-catalog} |
342
332
  | Enabled members | `worker:///_plurnk/members/*.md` | `<1,-1>`; {§members-projection} |
343
- | Project filesystem | `*` | File cap below; `project filesystem` |
344
- | Workspace entries | `worker:///*` | Markerless; `workspace entries` |
345
- | Named scratch entries | `worker://<worker>/*` | Markerless; `worker scratch` |
333
+ | Project filesystem | `*` | File cap below; `project root member files` |
334
+ | Workspace entries | `worker:///*` | Markerless; `workspace knowledgebase entries` |
335
+ | Named scratch entries | `worker://<worker>/*` | Markerless; `worker knowledgebase entries` |
346
336
 
347
337
  Only the three namespace surveys carry asides; the other targets name
348
338
  their surface. The word `skills` names Agent Skills and nothing else.
@@ -351,8 +341,8 @@ supplies examples and complete instructions on demand. A shallow
351
341
  result renders direct entries normally and every deeper first-segment directory
352
342
  as an actionable `dir/**` summary with its recursive `items` and `tokens`;
353
343
  tool-family rows also carry the concise `{§scheme-catalog-aside}` that drives
354
- on-demand capability discovery. Ordinary surveys use FIND's markerless first-16
355
- page, whose range metadata reports the requested and returned page against the
344
+ on-demand capability discovery. Ordinary surveys use FIND's markerless first
345
+ page ({§markerless-first-page}), whose range metadata reports the requested and returned page against the
356
346
  complete result total; only the small capability-reference surfaces
357
347
  explicitly select all. The opening survey demonstrates both `*` and `**` without
358
348
  normalizing an all-results override. Every survey executes even when empty
@@ -362,7 +352,14 @@ direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
362
352
  unset / `0` disables previews. `log://` is absent because the current worker's
363
353
  log already renders in present mode.
364
354
 
365
- §worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its program is stored before execution and dispatches the orienting READ/FIND surveys, the reasoning and program READs in {§reasoning-initial-read}, and the final TASK (in {§op-execution-order}). The prompt is not READ here: its `prompt` row in the first model turn is the one publication of every prompt ({§prompt-entry}), so the body never appears twice. The full `<1,-1>` READ of its own `ops:///<loop>/<turn>` source supplies the worked program example; no actionless source row or simulated READ is added. Every orienting row is structurally classified `_plurnk` and `init`. The program archives nothing: the prompt entry ({§prompt-entry}) is the durable, addressable copy of every prompt, so no scratch archive of it is written. The three namespace surveys carry asides that name what each space is — `project root member files`, `shared worker Extended Context`, `private worker Extended Context` — and, because the program echo shows them verbatim, those asides are the model's map of its spaces. TASK hands off with one {§plan-value} entry: `{"content":"Address the prompt.","status":"in_progress"}`. The first model request occupies the following turn and therefore begins at database/log turn sequence 2; “turn zero” is the initialization phase's model-facing label, not a zero-based database coordinate. Client and `_plurnk` administrative workers execute operation turns and do not receive model initialization.
355
+ §worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its reasoning and program are stored before execution. NOTEs from its reasoning and program, the orienting READ/FIND surveys, and the reasoning and program READs in {§reasoning-initial-read} execute under {§op-execution-order}. The full `<1,-1>` READ of its own `ops://<worker>/<loop>/<turn>` source supplies the worked program example; no actionless source row or simulated READ is added. Every orienting row is structurally classified `_plurnk` and `init`. The namespace surveys and their asides follow {§actor-boundary-catalog-preview}.
356
+
357
+ Incoming messages publish once as inbound SEND rows in the first model turn
358
+ ({§message-arrival}); initialization neither READs nor archives them. The turn
359
+ continues without a lifecycle declaration. The first model
360
+ request occupies database/log turn sequence 2; “turn zero” names the
361
+ initialization phase, not a zero-based database coordinate. Client and
362
+ `_plurnk` administrative workers execute operation turns without model initialization.
366
363
 
367
364
  ### §machine-processes Workspace and worker state
368
365
 
@@ -378,7 +375,7 @@ flowchart TB
378
375
  workspace --> parentEntries["Named scratch<br/>worker://a/..."]
379
376
  parent --> parentWork["Loops, turns, cancellation scope"]
380
377
  parent -->|FORK| child["Worker B"]
381
- parentLog -.->|"copy rows, tags, visibility state"| childLog["Worker B log"]
378
+ parentLog -.->|"copy rows and visibility state"| childLog["Worker B log"]
382
379
  parentEntries -.->|"snapshot under new name"| childEntries["Named scratch<br/>worker://b/..."]
383
380
  workspace --> childEntries
384
381
  child --> childLog
@@ -399,9 +396,9 @@ terminal history.**
399
396
  | Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
400
397
  | Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
401
398
  | Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
402
- | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Durable events, curation effects, tags, current active/body-suppression projection, and the matching observation cursor are copied as terminal history. Parent-audience occurrences still pending at the fork boundary belong to the snapshot; later sibling activity does not. |
399
+ | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Durable events, curation effects, current active/body-suppression projection, and the matching observation cursor are copied as terminal history. Parent-audience occurrences still pending at the fork boundary belong to the snapshot; later sibling activity does not. |
403
400
  | §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but turn-attached inference calls, their specializations, admission rows, and physical provider requests are not: one issued call or request has one causal branch. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
404
- | §machine-processes-entry-inheritance **Named scratch and evidence** | Workspace | FORK snapshots quiescent `worker`, `prompt`, and `reasoning` entries whose authority is the source Worker name into the child name. Bytes, attributes, and channel results remain exact; embedded addresses are not rewritten. Other resources, including `worker:///_plurnk/**`, stay shared. |
401
+ | §machine-processes-entry-inheritance **Named scratch and evidence** | Workspace | FORK snapshots quiescent `worker` entries whose authority is the source Worker name into the child name. Bytes, attributes, and channel results remain exact; embedded addresses are not rewritten. Other resources, including `worker:///_plurnk/**`, stay shared. |
405
402
  | Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
406
403
 
407
404
  §worker-fork-trigger **The branch's claimed row is the fork.** `worker_name_claim` with a fork
@@ -437,13 +434,10 @@ existing workspace worker in its own right.
437
434
  §worker-provider-identity **A worker owns a durable provider identity distinct
438
435
  from its database id.** Creation mints a globally unique, opaque 128-bit value;
439
436
  forks mint their own value. Core supplies it as the provider `workerId` for every
440
- emission and supplies the lineage root's value as `primaryWorkerId`
441
- ({§provider-cache-identity}). Database ids remain the internal relational and
437
+ emission ({§provider-cache-identity}). Database ids remain the internal relational and
442
438
  client coordinate. BARE calls use isolated per-call provider identities rather
443
439
  than either worker value.
444
440
 
445
- §worker-primary **The primary worker is the lineage root.** The PRIMARY worker of a turn's lineage is the no-parent root reached by walking `parent_worker_id` up; a no-parent worker is its own primary. Core supplies it on the first-party metadata channel alongside `Worker-Id` (same gate, computed per turn), stamped on EVERY turn including the primary's own (where it equals `Worker-Id`) — absent-with-a-Worker-Id is a contract violation, never a silent "assume primary." An unresolvable root (a corrupt/cyclic parent chain the `parent != id` CHECK forbids) fails hard. Providers emits it as `Plurnk-Worker-Primary`; a consumer routes primary-vs-spawned by equality (`Worker-Primary == Worker-Id` ⇒ the primary; `!=` ⇒ any-depth spawn, no depth math) and groups the worker tree by the shared root.
446
-
447
441
  §machine-processes-fork-shares-the-world **A fork copies history and named
448
442
  scratch while sharing the workspace.** It is a new worker in the
449
443
  same workspace (`workers.parent_worker_id`, {§lifecycle-terms}); project files,
@@ -460,7 +454,7 @@ or membership overlay requires a new workspace.
460
454
 
461
455
  §worker-name-minting **URI ingestion is permissive; worker minting is not.**
462
456
  Every model/client worker-creation door applies the contracts-owned
463
- `WORKER_NAME` predicate through one core admission path. Generic URL parsing
457
+ `WORKER_NAME` predicate ({§worker-name}) through one core admission path. Generic URL parsing
464
458
  continues to decompose other authorities without treating them as mintable.
465
459
 
466
460
  | Candidate | Minting result |
@@ -473,7 +467,7 @@ continues to decompose other authorities without treating them as mintable.
473
467
 
474
468
  §worker-write-scoping **Scratch is workspace-writable.** All workspace actors may EDIT, COPY, MOVE, or KILL entries in any named or shared scratch namespace, including generated documents. There is no creator-only, self-only, ancestor-only, or runtime-only grant. Workspace admission remains uniform. Intrinsically immutable evidence in other schemes retains its own contract ({§scheme-entry-matrix}); operation provenance and delegation lifecycle do not grant or restrict scratch access.
475
469
 
476
- §worker-generated-subtree **Generated documents share `worker:///_plurnk/`.** Project instructions (`agents.md` and subtree-scoped `instructions/**`), scheme/runtime references (`plurnk/**`), tool details (`tools/**`), and family catalogs are workspace resources. Agent Skills retain their own trees at `skill://<name>/` ({§skills-resources}).
470
+ §worker-generated-subtree **Generated documents share `worker:///_plurnk/`.** Project instructions (`AGENTS.md` and subtree-scoped `instructions/**`), scheme/runtime references (`plurnk/**`), tool details (`tools/**`), and family catalogs are workspace resources. Agent Skills retain their own trees at `skill://<name>/` ({§skills-resources}).
477
471
 
478
472
  The subtree has ordinary scratch access, not an ACL. Runtime maintenance reconciles it from workspace Functionality through the runtime actor's ordinary turns ({§actor-boundary-doc-injection}); reconciliation may replace manual edits. There are no per-Worker copies or fork rederivation. A runtime's `resourcesPath` is relative to this root ({§tools-resource-materialization}).
479
473
 
@@ -526,31 +520,34 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
526
520
  own work is a fresh loop, so an inherited mid-flight loop never makes the
527
521
  branch look forever-live to the {§send-premature-terminate} gate.
528
522
  - §worker-scheme-fork-scratch **Forked scratch.** Named scratch and evidence are copied under the new name through {§machine-processes-entry-inheritance}. Parent and branch can edit either scratch namespace; their copies diverge independently.
529
- - §worker-spawn-no-branch **WORK and FORK take a worker path and a prompt, nothing else.** Branch
530
- delegation was removed outright (#396). A model manages git branches through ordinary
531
- the `git` runtime — never engine machinery.
532
- - §worker-delegation-inherits-policy **Fresh delegated loops inherit proposal disposition.** WORK, FORK, and SEND to an idle Worker carry the sender's proposal disposition. SEND into an active or parked loop leaves its immutable policy untouched. All workers share live workspace capability policy; delegation creates no capability snapshot or bound.
523
+ - §worker-delegation-inherits-policy **Fresh delegated loops inherit the sender's policy.** WORK, FORK, and SEND to an idle Worker carry the sender's complete loop policy, disposition and attendance alike. SEND into an active or parked loop leaves its immutable policy untouched. All workers share live workspace capability policy; delegation creates no capability snapshot or bound.
533
524
  - §worker-lifecycle-wake-requeue-not-terminal **A wake re-queue is not a terminal.** A conclusion-wake resumes a 202-blocked loop by re-queueing it (202 → 100); when that lands while the loop's own live drain is between turns, the drain **re-claims and continues** (atomic 100 → 102; the injected prompt is already the next turn). The internal re-queue is never reported as an outward terminal.
534
525
 
535
- - §worker-scheme-collect **Collect** — a worker's loop reaching a terminal status
536
- surfaces to its direct parent as an ambient delta ({§env-delta}): a `SEND` from
537
- `worker://<name>` carrying the loop's exact terminal operation result. **Every
538
- conclusion is born visible** (its body materialized into the parent's packet,
539
- not body-suppressed): a child's last message must reach the parent visible and
540
- awakening whatever the status, never a bodyless row, because a failure's
541
- explanation is its deliverable (operator, 2026-09-14: fail is completed with a
542
- frowny face); a failure retains its exact status and Problem beside that
543
- message. Every death-path is stamped uniformly —
544
- including a spawn that dies before its first turn — so no child termination is
545
- silent to its owner; collection is lineage
546
- supervision, never a
547
- verb. The **pull** side mirrors the push: a path-absent
526
+ - §worker-scheme-collect **Collect** — each concluded child loop reaches its direct
527
+ parent as an `_plurnk` READ of `ops://<name>/<sequence>` ({§loop-answer}), not a message,
528
+ and that row carries what the child said.
529
+ The occurrence retains that loop's exact terminal result; the READ uses ordinary
530
+ bounded projection. Its body, when present, is initially visible. Replies are
531
+ independent deliveries ({§message-reply-delivery}), never copied into this outcome. Failures and
532
+ cancellations retain their exact status, Problem, and visible explanation,
533
+ including a spawn that fails before its first turn. Observation and wake-up
534
+ follow {§env-delta-child-termination}; a later child loop cannot replace the
535
+ retained result. The **pull** side mirrors the push: a path-absent
548
536
  ```` ```READ (worker://<name>) ```` collects that same result on demand for a
549
- concluded worker; **unfinished work**, including a future scheduled task, has not delivered, so the READ
550
- returns **425** (Too Early). TASK independently chooses whether to continue
537
+ concluded worker and names its canonical loop URI in `resource`; **unfinished loops** have not concluded, so the READ
538
+ returns **425** (Too Early). An explicit lifecycle declaration chooses whether to continue
551
539
  or wait for that worker ({§join-blocking-collect}). A
552
540
  missing name is 404. The model therefore reads the worker itself for its
553
541
  outcome or a wait rather than guessing a scratch path to "check on" it.
542
+ - §worker-loop-result `ops://<name>/<sequence>` selects one worker-local positive safe-integer
543
+ loop sequence ({§loop-answer}; the retired `loop://` scheme is gone, and one address now serves
544
+ both what a loop said and how it ended). It is a read-only resource, not an actor control
545
+ address: READ, FIND and COPY use ordinary projections; EDIT, MOVE-source, and KILL cannot change
546
+ it. No query, userinfo, or port is accepted. A coordinate that is not a positive safe integer is
547
+ 400; a missing loop 404; a loop that has not answered and has not concluded 425. A concluded
548
+ loop remains readable after newer loops, log curation, or a reply to its originating message.
549
+ A failure reports its problem even when the loop answered earlier: the failure is the news.
550
+ READs and completion observations use the same resolution, representation and projector.
554
551
  - §child-orientation **Child orientation.** Beyond the conclusion delta, every
555
552
  turn the packet's status clump surfaces the live things this worker currently
556
553
  holds under the teaching's own word for handing work out: `## Delegation` is
@@ -560,11 +557,13 @@ the `git` runtime — never engine machinery.
560
557
  history; this section is the current inventory that keeps an active obligation
561
558
  visible even when no new activity arrived. Each open stream pointer carries
562
559
  its channels' sizes and growth since the last packet in `detail`
563
- (`{"status":"active","path":"sh:///1/2/3/sh","detail":"stdout 340 lines (+2048 bytes)"}`)
560
+ (`{"status":"active","path":"sh:///ab3d5678","detail":"stdout 340 lines (+2048 bytes)"}`)
564
561
  — the only thing the model learns about a stream before it closes
565
562
  ({§exec-stream}). It is orienting state, never advice: the model sees its live
566
563
  subtree (`{"status":102,"path":"worker://worker-x"}`) and reasons for itself —
567
564
  READ, SEND, or KILL via the path.
565
+ Workspace schedules are not held work: an occurrence arrives as a message
566
+ ({§schedule-delivery}).
568
567
  - §packet-empty-sections **Emptiness is stated where the model decides on it.**
569
568
  `## Delegation` renders every turn, each of its two lists `[]` when empty: the
570
569
  model decides whether to wait or complete on exactly these facts, so their
@@ -576,8 +575,8 @@ the `git` runtime — never engine machinery.
576
575
  - §packet-current-turn **The packet says who and which turn, below the log.** The
577
576
  `## Worker` block is the first section after the log, carrying
578
577
  `{"path": "worker://<name>", "parent": <address or null>, "loop": L, "turn": T}`: the actor,
579
- whose child it is, and the coordinate this packet's response becomes, so `reasoning:///L/T`
580
- and `ops:///L/T` are the model's own and `log:///L/T/*` its rows; a model never infers the
578
+ whose child it is, and the coordinate this packet's response becomes, so `reasoning://<worker>/L/T`
579
+ and `ops://<worker>/L/T` are the model's own and `log:///L/T/*` its rows; a model never infers the
581
580
  present from the last row's coordinate, which may or may not be its own turn. The block
582
581
  changes every turn, so nothing of it precedes the log, and the packet carries no date, time
583
582
  or zone anywhere (operator, 2026-09-13: no date or time injection, and nothing volatile above
@@ -627,8 +626,6 @@ under that exact URL—never raw HTML, response headers, or a channel-selection
627
626
  lesson. FIND consumes the addressed stored channel representation
628
627
  and never re-fetch a match.
629
628
 
630
- §web-retrieval-live Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin materialize→FIND and persistence/publication separation. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page; live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions.
631
-
632
629
  **Git is the substrate and the repository is the boundary:**
633
630
 
634
631
  - §membership-baseline **The baseline contract — chiseled (#400).** To a workspace a
@@ -652,7 +649,7 @@ and never re-fetch a match.
652
649
  ({§membership-create-parents}). Admitted by a published standard as projected
653
650
  instruction documents — never as members: (3) the project's `AGENTS.md` and nested
654
651
  `AGENTS.md` files ({§turn0-agents-stunt}, #346), read from disk regardless of git status
655
- and materialized as `worker:///_plurnk/agents.md` and
652
+ and materialized as `worker:///_plurnk/AGENTS.md` and
656
653
  `worker:///_plurnk/instructions/<subtree>/AGENTS.md`; the file itself is a member
657
654
  only when tracked or added, and the standard never overrides the operator's
658
655
  exclusions — an `AGENTS.md` the repository ignores or an exclusion matches
@@ -725,7 +722,7 @@ reconsidered when the operator changes the policy and otherwise remains a stat-o
725
722
  no-op. The file write gate independently stats the source against the same ceiling,
726
723
  so safety does not depend on a background warm winning a client-operation race.
727
724
 
728
- §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row and one symbol graph without copying. The identity hashes the representation's own SHA-256 ({§tokenomics-content-hash-identity}), never its body, so a maintenance pass judges an entry channel from its stored `content_hash` without the body crossing into the process; a body is acquired only for a derivation that runs, under that same identity (a representation that moved on since it was judged returns nothing and is judged again next pass), or for a channel with no stored identity, an open or streamed channel, which must be read to be judged. Log rows and turn sources still arrive whole. The pass reports the bytes it acquired beside the derivations it ran, and an unchanged workspace acquires none of its channel bodies at any concurrency. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every launched worker settles before the maintenance pass reports success or failure, so one failed artifact cannot orphan sibling derivations. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
725
+ §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row and one symbol graph without copying, and the FTS index reads its text from the content store ({§content-store}) instead of keeping a copy. The identity hashes the representation's own SHA-256 ({§tokenomics-content-hash-identity}), never its body, so a maintenance pass judges an entry channel from its stored `content_hash` without the body crossing into the process; a body is acquired only for a derivation that runs, under that same identity (a representation that moved on since it was judged returns nothing and is judged again next pass), or for a channel with no stored identity, an open or streamed channel, which must be read to be judged. Log rows and turn sources still arrive whole. The pass reports the bytes it acquired beside the derivations it ran, and an unchanged workspace acquires none of its channel bodies at any concurrency. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every launched worker settles before the maintenance pass reports success or failure, so one failed artifact cannot orphan sibling derivations. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
729
726
 
730
727
  The artifact also retains a positive `{§mimetype-parse-issues}` count and the
731
728
  full normalized `{§mimetype-summary}` when the exact parsed channel reported
@@ -783,14 +780,14 @@ explicit.
783
780
 
784
781
  ## §worker-loop-lifecycle Loop scheduling and lifecycle
785
782
 
786
- - §join-blocking-collect **Collection and scheduling are independent.** A path-absent ```` ```READ (worker://<running-child>) ```` returns **425** (Too Early), without a strike or scheduler side effect. TASK with waiting intent joins live obligations; an `in_progress` inventory keeps working. A child reaching any terminal status wakes a waiting parent with its result, including completion racing the park boundary. Children retain their own limits; TASK timing may additionally bound the parent's wait. Collection never arms an implicit disposition override.
783
+ - §join-blocking-collect **Collection and scheduling are independent.** A path-absent ```` ```READ (worker://<running-child>) ```` returns **425** (Too Early), without a strike or scheduler side effect. WAIT joins live obligations; ordinary operations without WAIT keeps working. A child reaching any terminal status wakes a waiting parent with its result, including completion racing the park boundary. Children retain their own limits. Collection never arms an implicit disposition override.
787
784
 
788
785
  A worker is a **log plus a cancellation scope** — one `AbortController` per worker, reused while live and replaced only once aborted, so a cancel ends the worker as a unit and a later `runLoop` request is never born cancelled. A worker's queued loops are advanced by a **drain**: a single per-worker drain that claims loops atomically (status 100→102) and runs each under the worker's scope. A loop may spawn **streams** (execs) that outlive it; each is a row in the subscription registry ({§subscriptions}) — the durable record of what the worker holds open. Cancellation and conclusion are defined against these structures, never wall-clock timing.
789
786
 
790
787
  ```mermaid
791
788
  stateDiagram-v2
792
789
  [*] --> Queued: runLoop request
793
- Queued --> Running: due task claimed by drain
790
+ Queued --> Running: queued task claimed by drain
794
791
  Running --> Parked: wait with live obligations
795
792
  Parked --> Queued: obligation settles or arrival
796
793
  Running --> Terminal: conclude or fail
@@ -807,80 +804,21 @@ newer terminal loop cannot mask older queued, running, or parked work. Name
807
804
  collision, workspace worker caps, child obligations, orientation, and recovery
808
805
  all use that one definition.
809
806
 
810
- ### §worker-scheduled-send Scheduled worker tasks
811
-
812
- A numeric scope on `SEND (worker://name)` queues a new task with the authored
813
- body, even when the recipient has unfinished work. Unscoped SEND retains its
814
- ordinary arrival semantics. Timing is whole minutes, not text coordinates.
815
-
816
- | Directed SEND scope | First occurrence | Subsequent occurrences |
817
- |---|---|---|
818
- | `<D>`, `D ≥ 0` | Eligible after D minutes. | None. |
819
- | `<D,I>`, `D ≥ 0`, `I > 0` | Eligible after D minutes. | Fixed cadence of I minutes from the initial due time. |
820
-
821
- - Queued tasks carry a durable due time and the recipient's model selection,
822
- sender's delegated policy, and original prompt source. They do not activate
823
- provider inference or workspace Functionality before eligibility. Due tasks are
824
- claimed in queue order; an earlier future task cannot block ready work.
825
- - A recurrence has at most one unfinished occurrence. A successful terminal
826
- transition atomically queues its successor; all-failed inventory, engine failure, and
827
- cancellation queue none. Continuing or waiting TASKs retain the same occurrence and limits.
828
- - At first claim, overdue ticks coalesce into the latest due cadence slot. There is
829
- no catch-up backlog. Each occurrence has its own loop/turn/execution limits
830
- and the original task's generation/capability snapshot; injected corrections
831
- and response bodies are not recurrence instructions. Resuming a wait neither
832
- rechecks the occurrence's initial delay nor changes its selected cadence slot.
833
- - Ownership is the existing durable recipient worker and lineage, never its
834
- reclaimable name. Future queued work remains live for parent obligations,
835
- cancellation, name collision, and model-policy protection. KILL cancels its
836
- current and future work; later explicit SEND may authorize new work.
837
- - Restart retains queued and parked occurrences and their due times. Interrupted
838
- active work follows the ordinary owner-loss failure rule, without replaying
839
- uncertain effects or automatically rearming a failed recurrence.
840
- - Ordinary loop inspection exposes due time, recurrence identity, and interval.
841
- SEND acknowledges the accepted task identity and timing. Parent orientation
842
- includes queued future tasks; a completed occurrence is not a concluded
843
- recurring assignment.
844
-
845
- ```mermaid
846
- stateDiagram-v2
847
- [*] --> Queued: explicitly scheduled task
848
- Queued --> Running: due claim; coalesce elapsed ticks
849
- Running --> Parked: TASK waiting
850
- Parked --> Queued: same occurrence wakes
851
- Running --> Success: TASK terminal with at least one completed item
852
- Success --> Queued: atomic successor for recurrence
853
- Success --> [*]: one-shot
854
- Running --> Failed: TASK all failed, or engine failure
855
- Queued --> Cancelled: KILL
856
- Parked --> Cancelled: KILL
857
- Running --> Cancelled: KILL
858
- Failed --> [*]
859
- Cancelled --> [*]
860
- ```
861
-
862
807
  ### §worker-wait-timing Durable waits and wake ownership
863
808
 
864
- With waiting intent, an explicit finite TASK deadline or positive poll interval is itself
865
- a live obligation. A wake continues the same loop with the same prompts,
866
- generation policy, and cumulative turn ceiling; it never creates another assignment.
867
-
868
- | TASK scope with waiting intent, in minutes | Deadline | Observation |
869
- |---|---|---|
870
- | absent / `<-1>` | No clock deadline; join existing work. | Inherit open streams' polling policy; child completion is event-driven. |
871
- | `<T>`, `T ≥ 0` | Resume no later than T, even without a child or stream. | Inherit open streams' polling policy. |
872
- | `<T,P>`, `P > 0` | T as above, or unbounded for -1. | Resume after P, or earlier on deadline, completion, or a message. |
873
- | `<T,0>` | T as above. | Disable periodic observation for this wait; events and deadline still wake it. |
874
-
875
- Polling observes, never repeats operations. A wake ends this wait; a subsequent
876
- waiting TASK is a new wait with its own timing. Deadline expiry does not cancel a child
877
- or declare its execution failed. Ordinary terminal and cancellation rules
878
- remain authoritative.
809
+ WAIT has no timing operand; its optional path is a label ({§send-wait-scope}).
810
+ With live work—an open stream or a live child worker—the loop parks durably
811
+ and wakes on settlement, on a
812
+ message, or on the inherited observation cadence of its open streams
813
+ ({§exec-lifetime}); without live work it continues at once, told so. A wake
814
+ continues the same loop with the same messages, generation policy, and
815
+ cumulative turn ceiling; it never creates another assignment. Scheduled messages
816
+ exist independently of a loop's optional attachment to one occurrence.
879
817
 
880
818
  ```mermaid
881
819
  stateDiagram-v2
882
- Running --> Parked: atomically persist wait identity and timing
883
- Parked --> Queued: arrival / completion / due clock, guarded by wait identity
820
+ Running --> Parked: atomically persist the wait identity
821
+ Parked --> Queued: arrival / completion / inherited observation, guarded by wait identity
884
822
  Parked --> Terminal: cancellation
885
823
  Queued --> Running: same loop claimed by its worker's drain
886
824
  ```
@@ -893,18 +831,35 @@ obligations, not merely its latest parked loop. A completion crossing an active
893
831
  loop's park boundary is owed to that loop, never a future unrelated loop.
894
832
 
895
833
  Each loop captures the worker's completion revision when its program begins.
896
- Stream closure and direct-child terminalization advance that revision in the
897
- same database mutation as their terminal evidence. An unobserved completion
898
- remains owed through parking and restart; another loop's turn cannot consume
899
- it. Waking is guarded by both the wait identity and the relevant due/event
900
- predicate, so delayed callbacks do not wake programs that already observed
901
- their evidence.
902
-
903
- Wait identity and requested timing commit with the parked transition. SQLite
904
- owns due times; process timers only arrange a bounded next check. A restart
905
- retains future timed waits and reconciles elapsed ones once. Waking or
906
- terminalizing invalidates the old wait. Duplicate and racing wakes have one
907
- durable winner, and cancellation cannot be reversed by a timer.
834
+ Before inference, it acknowledges the current revision only after every addressed
835
+ terminal/reply occurrence has crossed the ambient observation cursor and every
836
+ closed stream has published its terminal channels. The publication check and
837
+ revision acknowledgement are atomic; an arrival beyond either materialization
838
+ snapshot remains owed. Stream closure, direct-child terminalization and addressed
839
+ replies advance the revision in the same database mutation as their evidence.
840
+ An unobserved completion remains owed through parking and restart; another loop's
841
+ turn cannot consume it. Waking is guarded by both the wait identity and the
842
+ relevant due/event predicate, so delayed callbacks do not wake programs that
843
+ already observed their evidence.
844
+
845
+ Wait identity commits with the parked transition. The drain persists any
846
+ inherited stream-observation due time; process timers only arrange a bounded
847
+ next check. Restart reconciles obligations under {§worker-lifecycle-restart-recovery}.
848
+ Waking or terminalizing invalidates the old wait. Duplicate and racing wakes
849
+ have one durable winner, and cancellation cannot be reversed by a timer.
850
+
851
+ §loop-claim-latency **A loop's first claim is durable.** `loops.claimed_at` is
852
+ stamped by trigger the first time a loop enters status 102, at insertion for a
853
+ loop created running and on the move from queued otherwise; later re-claims never
854
+ move it. The digest reports, per loop, the claim time and how long after it the
855
+ first model turn started, so a stall between claim and inference (a heartbeat has
856
+ waited 7.5 h, #703) is a number rather than a gap.
857
+
858
+ §digest-storage **The digest states the file's health.** Beside the database path it
859
+ reports the file size, the free pages it holds, its `auto_vacuum` mode, and the six
860
+ largest tables and indexes by allocated bytes (`dbstat`), so growth is a number in
861
+ every digest (#764). The digest reads loops as stored, so a database made before a
862
+ lifecycle column was added still digests.
908
863
 
909
864
  §loop-execution-allowance **One task has one execution allowance.** The first
910
865
  execution snapshots `PLURNK_SERVICE_LOOP_TIMEOUT` on the loop. Active segments
@@ -926,21 +881,21 @@ superseded exclusive lineage permission.
926
881
  An exhausted allowance aborts in-flight execution and produces `504`; a late
927
882
  callback cannot override a committed disposition. Restart preserves parked
928
883
  allowances; interrupted active tasks follow ordinary owner-loss recovery,
929
- never replay interrupted effects to reconstruct time. Wait deadlines remain
930
- the separate wall-clock scheduling contract above.
884
+ never replay interrupted effects to reconstruct time. Future messages use
885
+ the separate schedule contract ({§schedule-delivery}).
931
886
 
932
887
  §worker-message-admission **Recipient selection and admission are one decision.**
933
888
  An arrival to a worker selects its running loop, otherwise its oldest parked
934
889
  loop, otherwise a new queued loop. Compatibility is checked against the exact
935
- loop that receives the prompt; the writer does not reselect another recipient.
936
- The worker's admission lock covers selection, compatibility, prompt publication,
890
+ loop that receives the message; the writer does not reselect another recipient.
891
+ The worker's admission lock covers selection, compatibility, message admission,
937
892
  and the park-boundary wake check against orphan recovery. Fresh task insertion
938
893
  includes its complete generation policy, proposal disposition, and initial paths
939
894
  atomically; no drain may claim partially configured work.
940
895
 
941
896
  | Message at the receiving task's end | Disposition |
942
897
  |---|---|
943
- | Delivered to an unfinished loop | Append one ordered prompt frame; waking does not repeat earlier frames. |
898
+ | Delivered to an unfinished loop | Append one ordered message to the loop's inbox; waking does not repeat earlier messages. |
944
899
  | Admitted but not observed before ordinary completion | Preserve through the existing orphan-message admission path. |
945
900
  | Cancelled as part of the worker scope | Preserve the frame as evidence; never promote it into executable work, including after restart. |
946
901
  | Explicit new arrival after cancellation | Admit under ordinary current worker policy; never revive a terminal loop. |
@@ -967,26 +922,24 @@ stateDiagram-v2
967
922
  Observed --> [*]
968
923
  ```
969
924
 
970
- | §worker-lifecycle-subscription-matrix Subscription state at a waiting TASK | Terminal observation already in a packet | Result |
925
+ | §worker-lifecycle-subscription-matrix Subscription state at WAIT | Terminal observation already in a packet | Result |
971
926
  |-------------------------------------------------------------------------|---:|---|
972
927
  | open | no | park; polling or closure may wake it |
973
928
  | closed, any status, empty or non-empty | no | continue directly to the observation turn |
974
929
  | closed, any status, empty or non-empty | yes | no stream obligation remains |
975
930
  | cancelled as part of worker cancellation | irrelevant | terminate the cancelled worker; never resurrect it |
976
931
 
977
- Polling observes a still-open stream; it never changes ownership or manufactures
978
- completion. Closure is always a wake edge regardless of polling mode.
932
+ Observation watches a still-open stream; it never changes ownership or manufactures
933
+ completion. Closure is always a wake edge.
979
934
 
980
- | §worker-lifecycle-poll-matrix execution poll marker | While open | On closure |
935
+ | §worker-lifecycle-poll-matrix stream | While open | On closure |
981
936
  |------------------------------------------------|---|---|
982
- | omitted | exponential-backoff observation wakes | resume once with terminal observation |
983
- | positive `P` | fixed-cadence observation wakes every `P` minutes | cancel cadence; resume once |
984
- | zero | no observation wakes | resume once |
985
- | turn-scoped `<0>` | reap at the next pre-turn boundary | surface the terminal outcome |
937
+ | any lifetime but `turn` | the daemon's exponential-backoff observation wakes ({§exec-lifetime}) | resume once with terminal observation |
938
+ | `[{"lifetime":"turn"}]` | reap at the next pre-turn boundary | surface the terminal outcome |
986
939
 
987
940
  The structured-concurrency sequence is identical whether a child performs an
988
- execution, retrieval, or pure inference. Intermediate child status is private to the
989
- child. Only the child's terminal loop result crosses the parent edge.
941
+ execution, retrieval, or pure inference. Intermediate status does not drain the
942
+ child obligation; explicit replies may arrive earlier ({§message-reply-delivery}).
990
943
 
991
944
  ```mermaid
992
945
  sequenceDiagram
@@ -994,9 +947,9 @@ sequenceDiagram
994
947
  participant C as Child loop
995
948
  participant S as Child stream
996
949
  P->>C: WORK or FORK
997
- P->>P: TASK waiting parks on live child
950
+ P->>P: WAIT parks on live child
998
951
  C->>S: execution opens subscription
999
- C->>C: TASK waiting parks on live stream
952
+ C->>C: WAIT parks on live stream
1000
953
  loop backoff, fixed cadence, or explicit arrival
1001
954
  S-->>C: optional progress observation
1002
955
  C->>C: continue or park
@@ -1017,16 +970,16 @@ sequenceDiagram
1017
970
  | cancelled or failed terminal | no | same wake/delivery path as success; outcome remains non-2xx |
1018
971
 
1019
972
  A stream's close status and a loop's terminal status are separate layers. A
1020
- stream may close 4xx/5xx and wake its worker to recover. TASK adjudicates the
1021
- loop's inventory independently of stream and message-delivery statuses
1022
- ({§send}). Only a concluded loop crosses the parent edge as the child's result.
973
+ stream may close 4xx/5xx and wake its worker to recover. The lifecycle resolver adjudicates the
974
+ loop's answered messages, observation boundaries, and held work independently of
975
+ stream and message-delivery statuses ({§send}). Only a concluded loop drains the child obligation.
1023
976
 
1024
977
  §worker-lifecycle-terminal-result **Terminal truth is a result, not a lifecycle code.** `loops.terminal_result`
1025
978
  stores the exact universal operation result. A failure therefore retains its
1026
979
  RFC 9457 Problem Details and exact status through persistence, restart,
1027
- parent collection, and `loop/terminated`; successful turn disposition content and
1028
- mimetype remain in the same result. Cancellation markers and branch receipts
1029
- are derived presentation, never a second stored outcome. The constrained `loops.status`
980
+ parent collection, and `loop/terminated`. Message delivery and execution outcome
981
+ are independent: neither completion nor cancellation borrows the last reply's body.
982
+ Cancellation markers are derived presentation, never a second stored outcome. The constrained `loops.status`
1030
983
  column remains only the scheduler's compact lifecycle projection: known
1031
984
  terminal classes remain themselves, other 2xx/3xx statuses project to `200`,
1032
985
  and other 4xx/5xx statuses project to `500`; exact `202` is forbidden because
@@ -1053,28 +1006,27 @@ observe their terminal results. No effect is replayed across an unknown
1053
1006
  boundary.
1054
1007
 
1055
1008
  - §worker-lifecycle-single-drain **One drain advances a worker.** At most one drain is registered for a worker at any instant: a `runLoop` request or wake on a worker with a live drain folds in (active→next-turn) or enqueues a loop that drain claims, never a second parallel drain. A drain's start and its empty-queue teardown relinquish the worker under one per-worker lock, so the teardown's re-claim cannot race a concurrent start into a double-drain. Fresh-loop sequence allocation and insertion are one mutation under that same lock; concurrent accepted prompts remain distinct ordered queue items.
1056
- - §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel`, worker `KILL`, and a failed TASK terminalize every unresolved loop in the cancelled worker subtree and iterate each worker's durable open-subscription rows, invoking each exact callable owner from the process-local live registry. The durable rows answer *what is held*; the live registry answers *how this process tears it down*; the abort signal is a fast-path optimization. There is no implicit detachment. Shutdown reaps process-local streams while preserving parked work under {§worker-lifecycle-durable-disposition}. Before shutdown awaits drains, it cancels every process-local proposal waiter through {§proposal-cancel-aborts} with outcome `daemon_stopping`, so a stopped-world dispatch cannot hold teardown open. A stream that is running, mid-spawn (its row written before it is killable), or spawned after the cancel is reaped alike. The teardown abort is bounded: the executor sends a polite signal then SIGKILL after a consumer-set grace (`PLURNK_SERVICE_EXEC_KILL_GRACE_MS`). A model ```` ```KILL [code] ```` on one live stream instead delivers exactly that signal once (bare KILL uses the executor's SIGHUP default; ```` ```KILL [9] ```` uses SIGKILL).
1009
+ - §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel` and worker `KILL` terminalize every unresolved loop in the cancelled worker subtree and iterate each worker's durable open-subscription rows, invoking each exact callable owner from the process-local live registry. The durable rows answer *what is held*; the live registry answers *how this process tears it down*; the abort signal is a fast-path optimization. There is no implicit detachment. Shutdown reaps process-local streams while preserving parked work under {§worker-lifecycle-durable-disposition}. Before shutdown awaits drains, it cancels every process-local proposal waiter through {§proposal-cancel-aborts} with outcome `daemon_stopping`, so a stopped-world dispatch cannot hold teardown open. A stream that is running, mid-spawn (its row written before it is killable), or spawned after the cancel is reaped alike. The teardown abort is bounded: the executor sends a polite signal then SIGKILL after a consumer-set grace (`PLURNK_SERVICE_EXEC_KILL_GRACE_MS`). A model ```` ```KILL [code] ```` on one live stream instead delivers exactly that signal once (bare KILL uses the executor's SIGHUP default; ```` ```KILL [9] ```` uses SIGKILL).
1057
1010
  - §worker-lifecycle-exec-epoch-bound **A stream's kill binds to the scope it captured at spawn.** A stream captures the worker's cancellation scope as it registers and wires its kill to it, re-checking `aborted` AFTER wiring — no check-then-listen gap can drop an abort that lands mid-registration. Because the scope is replaced only once aborted, a captured-then-replaced scope is necessarily already aborted, so replacement never strands a live stream.
1058
- - §worker-lifecycle-no-resurrection **Cancelled work does not revive its scope.** A cancelled worker cannot be woken by its torn-down streams, stale timers, or cancelled undelivered prompt frames. The evidence remains readable. A `499` result from cancelling only one stream is still a completion owed to a live waiting worker: result status is not proof of worker cancellation. Only an explicit new arrival admits new work after scope cancellation; terminal loops themselves remain immutable.
1059
- - §worker-cancel-trigger **A cancellation is one bound statement.** `lifecycle_cancel_workers` writes the causal cutoff and the cancellation Problem onto every worker of the scope; `workers_cancel_live_loops` (an `INIT` process trigger beside the lifecycle statements, {§db-process-triggers}) retires each worker's live loops inside that statement — 499, waits cleared, the delivered response kept as the result's `content`, the Problem instanced `loop:///<id>`, `terminated_by = 'cancel'` — so cutoff and cancellation cannot land apart and no value is string-interpolated. Execution consumption is measured by the process-local monotonic timers ({§loop-execution-allowance}) and lands first through `lifecycle_checkpoint_executions`; a wall clock cannot stand in for it, so the timer stays outside the database by design.
1060
- - §worker-causal-admission **Admission and cancellation have one ordering.** DrainSupervisor serializes message admission, prompt promotion, and subtree cancellation within the workspace, taking the worker queue lock inside that control boundary. No provider, tool, fork-history copying, or stream reap holds it. WORK, FORK, and directed SEND identify their originating loop; admission requires that task still running. An accepted message to an independent recipient is a committed effect, not retroactively withdrawn by cancelling its sender.
1011
+ - §worker-lifecycle-no-resurrection **Cancelled work does not revive its scope.** A cancelled worker cannot be woken by its torn-down streams, stale timers, or cancelled unpublished messages. The evidence remains readable. A `499` result from cancelling only one stream is still a completion owed to a live waiting worker: result status is not proof of worker cancellation. Only an explicit new arrival admits new work after scope cancellation; terminal loops themselves remain immutable.
1012
+ - §worker-cancel-trigger **A cancellation is one bound statement.** `lifecycle_cancel_workers` writes the causal cutoff and the cancellation Problem onto every worker of the scope; `workers_cancel_live_loops` (an `INIT` process trigger beside the lifecycle statements, {§db-process-triggers}) retires each worker's live loops inside that statement — 499, waits cleared, message evidence left unchanged, the Problem instanced `loop://<worker>/<sequence>`, `terminated_by = 'cancel'` — so cutoff and cancellation cannot land apart and no value is string-interpolated. Execution consumption is measured by the process-local monotonic timers ({§loop-execution-allowance}) and lands first through `lifecycle_checkpoint_executions`; a wall clock cannot stand in for it, so the timer stays outside the database by design.
1013
+ - §worker-causal-admission **Admission and cancellation have one ordering.** DrainSupervisor serializes message admission, orphan-message recovery, and subtree cancellation within the workspace, taking the worker queue lock inside that control boundary. No provider, tool, fork-history copying, or stream reap holds it. WORK, FORK, and directed SEND identify their originating loop; admission requires that task still running. An accepted message to an independent recipient is a committed effect, not retroactively withdrawn by cancelling its sender.
1061
1014
 
1062
1015
  | Boundary outcome | Durable consequence |
1063
1016
  |---|---|
1064
1017
  | Admission before cancellation | Owned work is included in cancellation. |
1065
- | Recurring success during cancellation | Its successor is cancelled and reported from the durable cutoff, not a previously sampled task list. |
1066
1018
  | Cancellation before admission | The cancelled task cannot deliver further messages or start children. Created identities and evidence are retained. |
1067
- | Cancellation with unread prompts on completed tasks | Atomically record each worker's greatest admitted loop sequence as `cancelled_through_sequence` and cancel unresolved tasks. Prompt promotion, including boot recovery, excludes sources at or below that cutoff; completed results and prompt evidence are unchanged. |
1019
+ | Cancellation with unpublished messages on completed tasks | Atomically record each worker's greatest admitted loop sequence as `cancelled_through_sequence` and cancel unresolved tasks. Orphan-message recovery, including boot recovery, excludes sources at or below that cutoff; completed results and message evidence are unchanged. |
1068
1020
  | Independent arrival after cancellation | Admit a new loop above the cutoff using the ordinary worker policy. |
1069
1021
  | Slow stream teardown after new admission | Reap only subscription identities captured by cancellation; late old-scope spawns follow {§worker-lifecycle-exec-epoch-bound}. |
1070
1022
 
1071
1023
  - §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** The stream first persists its terminal state. A worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) then **awakens that loop in place** — the blocked loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. An already-active worker needs no injected prompt or second wake because its next packet reads the durable terminal state. A concluded worker receives no synthetic loop from ambient stream closure. The result remains available in the stream's own state under every case.
1072
1024
  - §worker-lifecycle-child-wake **Each child task completion notifies its parent.** Terminal-task publication, including failure and cancellation of a parked task, notifies the direct parent without injecting a prompt. Other unfinished tasks or streams in that child remain independent obligations; they cannot suppress notification. The parent's eligible waits requeue in place under {§loop-wake-identity} and the bounded {§worker-optimistic-settlement} opportunity. Durable revisioning covers completion-before-park and restart; drain teardown and whole-worker quiescence are not completion identities.
1073
- - §worker-optimistic-settlement **Asynchronous settlement receives one bounded worker-local opportunity before model dispatch.** An initiating turn lets only the streams it started settle before its turn disposition; separately, a stream or direct-child conclusion persists and publishes immediately but holds eligible parked loops' `202→100` requeues while another stream or direct child remains live. Both use `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`, shipped at five seconds; zero disables the opportunity. The wake hold ends as soon as no sibling obligation remains, never extends its original deadline, and coalesces conclusions within that window into at most one requeue per eligible loop. With no sibling obligation the wake is immediate; at the deadline, surviving work follows the ordinary monitored lifecycle. A conclusion that lands after provider dispatch begins retains its next wake, while poll, park-deadline, prompt, and operator wakes never open this hold. Only packet/provider dispatch waits: terminal state, client events, cancellation, and child execution do not. One redaction-safe span records elapsed time, quiescence versus deadline, and conclusion count without entering the packet.
1074
- - §worker-lifecycle-idle-is-concluded **No implicit completion.** A waiting inventory without a finite deadline, positive poll or live obligation continues under {§wait-obligation-matrix}. Only a terminal inventory with at least one completed task claims success. A concluded worker retains durable history; a later addressed arrival starts a new loop.
1025
+ - §worker-optimistic-settlement **Asynchronous settlement receives one bounded worker-local opportunity before model dispatch.** An initiating turn lets only the streams it started settle before program completion; separately, a stream conclusion, direct-child conclusion or addressed reply persists and publishes immediately but holds eligible parked loops' `202→100` requeues while another stream or direct child remains live. Both use `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`, shipped at five seconds; zero disables the opportunity. The wake hold ends as soon as no sibling obligation remains, never extends its original deadline, and coalesces arrivals within that window into at most one requeue per eligible loop. With no sibling obligation the wake is immediate; at the deadline, surviving work follows the ordinary monitored lifecycle. An arrival after provider dispatch begins retains its next wake, while poll, new-request and operator wakes never open this hold. Only packet/provider dispatch waits: durable state, client events, cancellation and the replying program do not. One redaction-safe span records elapsed time, quiescence versus deadline, and arrival count without entering the packet.
1026
+ - §worker-lifecycle-idle-is-concluded **Idle is not unanswered.** An empty WAIT continues; an answered, observed program without held work concludes under {§wait-obligation-matrix}. A concluded worker retains durable history; a later addressed arrival starts a new loop.
1075
1027
  - §worker-lifecycle-no-lost-loop **A loop is never stranded by a drain's exit.** A drain relinquishes its registry slot only after a lock-held re-claim confirms the queue is empty; a loop enqueued during that teardown is either re-claimed by the exiting drain or claimed by a fresh drain that a later inject starts. The relinquish and the start are serialized, so neither the lost-loop hang nor a transient double-drain can occur.
1076
1028
  - §worker-lifecycle-durable-disposition **Durable disposition wins cancellation races.** At a turn boundary, the engine reads the loop's durable status before interpreting a process-local abort. A committed `202` park survives a later daemon-shutdown signal; only a loop still durably running at `102` can be terminalized by that cancellation. Wake selection rechecks shutdown and worker cancellation before requeuing each parked loop.
1077
- - §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every pending physical provider request first settles as an error with absent usage and explicitly unknown cost; then its logical model call closes. Recovery never fabricates zero evidence. Every durable proposed operation likewise lost its process-local resolution waiter and settles as a visible `500 owner_vanished` occurrence rather than an unresolvable interrupt ({§proposal-list}). A pending client interaction also lost its exact awaiting operation, so boot removes the orphan instead of replaying work or inventing a response ({§client-interactions}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation preserves its requested deadline and observation interval. An unseen completion requeues it; an untimed join whose obligations vanished also requeues. Otherwise a future timed wait remains parked and an expired due time wakes it through the same guarded scheduler. Child terminalization wakes its parked parent on every outcome, including provider exceptions, cancellation, and restart interruption, recursively through the durable parent edges. These operations are idempotent, so an interrupted recovery safely repeats.
1029
+ - §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every pending physical provider request first settles as an error with absent usage and explicitly unknown cost; then its logical model call closes. Recovery never fabricates zero evidence. Every durable proposed operation likewise lost its process-local resolution waiter and settles as a visible `500 owner_vanished` occurrence rather than an unresolvable interrupt ({§proposal-list}). A pending client interaction also lost its exact awaiting operation, so boot removes the orphan instead of replaying work or inventing a response ({§client-interactions}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation requeues on an unseen completion or when no live obligation remains. Otherwise it stays parked on surviving children; the drain restores inherited stream observation through the same guarded scheduler ({§worker-wait-timing}). Child terminalization wakes its parked parent on every outcome, including provider exceptions, cancellation, and restart interruption, recursively through the durable parent edges. These operations are idempotent, so an interrupted recovery safely repeats.
1078
1030
 
1079
1031
  ---
1080
1032
 
@@ -1088,7 +1040,7 @@ their absence never makes a client, plugin, or `_plurnk` turn exceptional.
1088
1040
  |---|---|
1089
1041
  | `producer` | Required actor class: `model`, `client`, `plugin`, or `_plurnk`. |
1090
1042
  | `kind` | Required purpose: `inference`, `initialization`, `operation`, or `maintenance`. Model iff inference; initialization and maintenance require `_plurnk`. Producer and kind are immutable. A maintenance turn's successful rows are packet-suppressed — a receipt answers an asker, and maintenance has none ({§actor-boundary-doc-injection}). |
1091
- | `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the exact turn disposition/operation disposition and timestamp; a completed 102 is therefore distinct from an open 102. |
1043
+ | `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the program outcome and timestamp; a completed 102 is distinct from an open 102. A successful administrative program completes at 200 without concluding its host model loop. |
1092
1044
  | Operations | Ordered by `(turn_id, sequence)` on one exact worker/loop/turn chain. Each row's `origin` is the turn producer or `_plurnk` making a system observation; the observation does not impersonate the producer. |
1093
1045
  | Program source | Every admitted source-backed turn preserves its exact program before dispatch in `turn_sources`, independently of log receipts, under {§turn-ops-entry}. |
1094
1046
  | Inference evidence | Model calls, `packet`, model, finish reason, and provider metadata belong only to model/inference turns. Turn fields are nullable until recorded and remain NULL for every other kind. |
@@ -1104,7 +1056,7 @@ recovery completes any turn whose producer vanished.
1104
1056
  A provider response, deterministic `_plurnk` program, or future client/plugin
1105
1057
  program crosses one admission boundary into the same executor. That executor
1106
1058
  parses once, dispatches the admitted statements in order, records their ordinary
1107
- outcomes, and completes the turn from its TASK ruling. Exact source is retained before dispatch.
1059
+ outcomes, and completes the turn from its lifecycle ruling. Exact source is retained before dispatch.
1108
1060
  Provider attempts, grammar recovery, reasoning, and accounting end before this
1109
1061
  shared seam. A programmatic operation batch that supplied no Plurnk source does
1110
1062
  not fabricate verbatim source.
@@ -1113,7 +1065,7 @@ not fabricate verbatim source.
1113
1065
  Immediately before statement dispatch, the shared executor captures that worker's
1114
1066
  append-only log high-water mark. Every log-targeted KILL in the program resolves
1115
1067
  row membership at or below that same boundary, while prior curation effects still
1116
- compose normally. Prompt and other pre-program rows already present in the turn
1068
+ compose normally. Message arrivals and other pre-program rows already present in the turn
1117
1069
  remain selectable; preceding and later operation rows cannot be captured by
1118
1070
  their own program. A directly dispatched
1119
1071
  single operation captures the equivalent boundary before dispatch. This limits
@@ -1129,7 +1081,6 @@ These are the complete strike sources:
1129
1081
  | Strike source | Exact trigger | Model-visible occurrence |
1130
1082
  |---------------------|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
1131
1083
  | Hard result | An admitted non-execution operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `425`, `501`. | The originating failure row. |
1132
- | Inventory steering | Retired (2026-09-14): a completion claimed over live work joins it ({§completion-joins-live-work}) and one over settled results defers ({§completion-defers-to-results}); every answer to a TASK claim, an empty inventory's soft 409 included, is a receipt and never a strike; a malformed TASK (`400 wait-timing-invalid`) is a hard result like any other operation's. | The TASK receipt. |
1133
1084
  | Cycle | The executed operations and their observed results repeat under {§engine-cycle-evidence}. | None; cycle detection itself is private engine accounting. |
1134
1085
 
1135
1086
  Execution results remain exact model-visible evidence but are always soft: an
@@ -1142,9 +1093,10 @@ other violations in the same turn still strike normally.
1142
1093
 
1143
1094
  §engine-cycle-evidence Cycle identity contains the ordered executed operations
1144
1095
  and their dispatch results, including complete operands, scopes, bodies, and
1145
- scheme metadata, including the complete TASK inventory and SEND bodies. Source
1096
+ scheme metadata, including the complete NOTE and response bodies. Source
1146
1097
  positions and asides are excluded. Engine-assigned
1147
- Problem `instance` addresses are excluded from results. Object member order is
1098
+ Problem `instance` addresses and NOTE's assigned storage `resource` coordinate
1099
+ are excluded from results; the complete note body still distinguishes activity. Object member order is
1148
1100
  irrelevant; operation and array order are preserved. Only the configured
1149
1101
  `MIN_CYCLES × MAX_CYCLE_PERIOD` history window is retained. Repeated addresses
1150
1102
  alone are not a cycle: changing inputs or observations distinguish activity.
@@ -1156,8 +1108,8 @@ effects. Ordinary contract strikes and operator budgets remain independent.
1156
1108
  call fails with a network failure, rate limit, deadline, or interrupted resource after
1157
1109
  the provider's own retries, the turn records the exact Problem as a `_plurnk` row,
1158
1110
  notices the client (`engine:provider` / `provider_unavailable`), waits with
1159
- exponential backoff (`PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF`, doubling, capped at
1160
- twelve times itself), and re-issues the same call against the exact frozen model
1111
+ exponential backoff (`PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF`, doubling up to
1112
+ `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX`), and re-issues the same call against the exact frozen model
1161
1113
  messages whose response is still outstanding. Each reissue remains a distinct logical
1162
1114
  model call with complete physical-request accounting, but the active turn's newly
1163
1115
  recorded provider Problems do not recursively enter that request; they surface normally
@@ -1166,8 +1118,10 @@ scored. Every recovery checkpoint broadcasts live, while the model-facing Notice
1166
1118
  retains only the current provider state; the next completed exchange notices
1167
1119
  `provider_recovered`. Recovery is bounded by `PLURNK_SERVICE_PROVIDER_RECOVERY`; when it
1168
1120
  is spent the turn completes as `202` and the loop parks exactly like a
1169
- TASK wait ({§worker-lifecycle-wake-requeue-not-terminal}), resuming on the
1170
- next prompt or wake with its log intact. Only a client cancel, the execution allowance
1121
+ WAIT ({§worker-lifecycle-wake-requeue-not-terminal}), resuming on the
1122
+ next prompt or wake with its log intact — **unless the run is unattended
1123
+ ({§loop-attendance}), in which case the loop concludes on the provider's exact failure
1124
+ instead, because parking stops the execution clock and no wake would ever arrive.** Only a client cancel, the execution allowance
1171
1125
  ({§operator-config-loop-timeout}), or a non-recoverable provider Problem (refusal,
1172
1126
  authorization, quota, an invalid response) settles a loop on a provider failure.
1173
1127
 
@@ -1183,15 +1137,14 @@ The contracts, and the violation of each that strikes:
1183
1137
  | Contract | Violation that strikes |
1184
1138
  |---|---|
1185
1139
  | operation contract | a hard operation failure (status ≥ 400) in an admitted turn — soft statuses below excluded |
1186
- | review contract | none since 2026-09-14: a completion claimed over live work joins it ({§completion-joins-live-work}), one over settled results defers ({§completion-defers-to-results}), and an empty inventory or an already-terminal loop is a soft receipt |
1140
+ | review contract | none: answered work joins live obligations ({§completion-joins-live-work}) or continues to observe results ({§completion-defers-to-results}) |
1187
1141
  | progress contract | a detected operation cycle (`MIN_CYCLES` × period), or an admitted turn with no operation ({§empty-turn}) |
1188
1142
  | frame contract | emission attempts exhausted with no admissible turn |
1189
1143
  | provider response contract | the provider returned an invalid response |
1190
1144
 
1191
1145
  Errors and issues are NOT contract violations. Each keeps its own disposition
1192
1146
  and never strikes: exploration misses (404, 416) and unsupported capability
1193
- (501) are how discovery works; raw 409 outcomes are soft (the review ruling is
1194
- steer's alone); execution outcomes and `executor/*` problem rows are world evidence;
1147
+ (501) are how discovery works; raw 409 outcomes are soft; execution outcomes and `executor/*` problem rows are world evidence;
1195
1148
  provider weather (rate limit, network failure, deadline, interruption) recovers
1196
1149
  ({§provider-recovery}); provider capacity has its own packet recovery and
1197
1150
  terminal ({§provider-capacity-failure}); request rejection
@@ -1201,9 +1154,7 @@ attempts are forensic evidence beneath their turn ({§emission-admission}) —
1201
1154
  only their exhaustion surfaces, as one frame-contract violation. The
1202
1155
  independent turn ceiling terminates at **429** ({§loop-terminals}). The streak
1203
1156
  and cycle verdict are absent from model packets; only the concrete occurrences
1204
- in the table are shown. The current streak may ride first-party provider
1205
- metadata ({§strikes-first-party-metadata}), which does not make it
1206
- model-facing.
1157
+ in the table are shown. The streak never leaves the daemon.
1207
1158
 
1208
1159
  §loop-rail-continuity Rail state belongs to the durable loop, not its execution
1209
1160
  segment. The strike streak and bounded cycle history survive driver cleanup and
@@ -1217,13 +1168,13 @@ restart; curation of log evidence cannot alter them.
1217
1168
  | Recoverable provider outage | No assessment; preserve the streak. | Preserve until an actual park. |
1218
1169
  | New loop | Start at zero. | Start empty. |
1219
1170
 
1220
- The turn belongs to the wait revision under which it began. A rejected waiting TASK or
1171
+ The turn belongs to the wait revision under which it began. A rejected WAIT or
1221
1172
  one resolved without parking does not close a window. Periodic observations
1222
1173
  separated by actual waits are not an uninterrupted cycle; cumulative turn and
1223
1174
  execution allowances remain independent bounds. A committed terminal result
1224
1175
  cannot be replaced by a later rail assessment ({§worker-lifecycle-state-machine}).
1225
1176
 
1226
- ## §provider Provider Contract
1177
+ ## Provider Contract
1227
1178
 
1228
1179
  Author-facing contract: [`@plurnk/plurnk-providers`](../plurnk-providers/SPEC.md). Below: consumption surface + engine→provider guarantees.
1229
1180
 
@@ -1241,7 +1192,7 @@ Three current entry points:
1241
1192
 
1242
1193
  §meta-passthrough **Metadata passthrough (provider → client).** `generate` may return an open `meta: Record<string, unknown>` bag. The service stores it unenforced per turn (`turns.meta`, `json_valid` only — no schema) and forwards the latest turn's blob in `loop/terminated.usage` ({§notifications}). The service never reads a field within it. Providers own their metadata shapes; monetary values carry an explicit amount and currency rather than an implied unit. Absent → `{}`. The mirror direction (client → provider, the self-identified `client` id) rides `generate({client})` ({§attribution}).
1243
1194
 
1244
- ### §provider-guarantees Engine → provider guarantees
1195
+ ### Engine → provider guarantees
1245
1196
 
1246
1197
  - `messages` is a complete prompt (the section list, pre-assembled into the system + user messages). Provider does not reorder.
1247
1198
  - §provider-guarantees-signal-wired `signal` is wired to the worker's AbortController.
@@ -1253,7 +1204,7 @@ Three current entry points:
1253
1204
 
1254
1205
  ### §emission-admission Provider emission admission
1255
1206
 
1256
- A completed provider exchange is an **emission attempt**, not necessarily an engine turn. ANTLR admits at least one parsed source operation, no `unparsedTail`, and at most one final TASK. Omitted TASK continues silently under {§turn-shape}, without a synthesized inventory, receipt, diagnostic, warning, or strike. Bounded operation errors retain useful siblings and participate in the ordinary struck turn; statements after TASK are admitted in authored order and the disposition is scheduled last ({§disposition-anywhere}). A duplicate TASK or an unfinished heading slot at the end of the input rejects the exchange; no recovered prefix dispatches. A missing closer never rejects ({§closer-fallback}). An exchange with no operation and no other hard error is not rejected: it is admitted as an empty turn ({§empty-turn}). Parser warnings remain admissible. `finish=length` is evidence of likely truncation, not an independent rejection rule. Provider-declared interruption never reaches admission ({§provider-interrupted-attempt}). Accepted source bytes and statement positions remain exact in response evidence and `turnOps`. Execution follows {§op-execution-order}.
1207
+ A completed provider exchange is an **emission attempt**, not necessarily an engine turn. **The harness admits every program whose meaning it can determine, runs what it admitted, and reports — never refuses — what it could not read**; a refusal is for undecidable text alone. ANTLR admits at least one parsed source operation. WAIT is optional under {§turn-shape}; omission invents no operation, diagnostic, warning or strike; any number of WAITs are one park, scheduled last ({§disposition-anywhere}), and statements after them remain admitted in authored order. Bounded operation errors retain useful siblings and participate in the ordinary struck turn. An unfinished heading slot ({§unparsed-tail-boundary}) refuses only what follows it: the statements that closed before it run, and the loss is one more hard diagnostic — a failed row with the lexer's own reason; an exchange that lost its boundary before any statement closed has nothing admissible and is rejected. A missing closer never rejects ({§closer-fallback}). An exchange with no operation and no other hard error is not rejected: it is admitted as an empty turn ({§empty-turn}). Parser warnings remain admissible. `finish=length` is evidence of likely truncation, not an independent rejection rule. Provider-declared interruption never reaches admission ({§provider-interrupted-attempt}). Accepted source bytes and statement positions remain exact in response evidence and `turnOps`. Execution follows {§op-execution-order}.
1257
1208
 
1258
1209
  §safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ or KILL only when splitting its raw target at top-level comma or whitespace separators produces at least two members and every member independently parses as an explicit `scheme://` URI. Request-metadata blocks are opaque to this split. Each member becomes one ordinary statement with an independent dispatch outcome and log row, in authored member order at that operation's position under {§op-execution-order}. Otherwise the target remains exactly singular, including local filenames containing spaces or commas. The stored `turnOps` and authored command count remain unexpanded, and no other operation admits target groups.
1259
1210
 
@@ -1262,16 +1213,16 @@ Core retries a rejected emission against the exact same packet beneath the same
1262
1213
  When the loop continues after exhaustion under {§invalid-emission-attempts}, the next ordinary turn's packet projects the latest rejected response visibly from a durably body-suppressed emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice: `Response rejected before dispatch; no operations were performed.` followed by `Parser: <the latest attempt's first diagnostic>` with its `content-offset` position — the model sees why, at which line, against its own projected text. The Notice states only observed admission facts; it does not classify the response as unrecoverable, infer why generation ended, or prescribe intent beyond the parser-owned diagnostic. Attempt count and rail state never become model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats that malformed body unless the model explicitly READs its exact address. Admission clears the recovery projection; another exhaustion replaces it with the latest rejected response if the loop continues.
1263
1214
 
1264
1215
  Outside-block text has no execution, message, or receipt semantics under
1265
- {§whitespace-contract}. The `ops:///` source retains it verbatim under
1216
+ {§whitespace-contract}. The `ops://<worker>/` source retains it verbatim under
1266
1217
  {§turn-ops-log-curation}; execution never reconstructs source from the AST.
1267
1218
 
1268
- An admitted program may contain bounded malformed statements.
1269
- Parsed operations still dispatch; each hard parser diagnostic
1270
- becomes one durable model-origin `error` row with the parser's exact detail under
1271
- {§parse-diagnostics} and status 400. These failures are committed before the
1272
- explicit final TASK, or at the end of a TASK-less program, participate in the ordinary strike rail, and prevent completed
1273
- inventories from concluding before the model sees them in the next packet.
1274
- A waiting inventory without a live obligation continues to those results.
1219
+ An admitted program may contain bounded malformed statements, or end in a lost
1220
+ boundary. Parsed operations still dispatch; each hard parser diagnostic — the
1221
+ tail's reason included — becomes one durable model-origin `error` row with the
1222
+ parser's exact detail under {§parse-diagnostics} and status 400. These failures are committed before the
1223
+ explicit WAIT, or at the end of a program without WAIT, participate in the ordinary strike rail, and prevent
1224
+ completion before the model sees them in the next packet.
1225
+ WAIT without a live obligation continues to those results.
1275
1226
  This is operation recovery, not provider
1276
1227
  resampling. A malformed statement's Problem records the factual
1277
1228
  `siblingsRetained: true` extension.
@@ -1314,9 +1265,7 @@ Runtime hooks are synchronous and receive only the attempt coordinates. A hook
1314
1265
  failure is an internal plugin-contract failure; Core does not silently discard
1315
1266
  it or reinterpret a malformed tag list.
1316
1267
 
1317
- §strikes-first-party-metadata The loop's **current strike streak** rides `generate({ strikes })` the same way — first-party outbound metadata (`Plurnk-Strikes` under the `firstPartyMetadata` gate): the hosted router's escalation signal (route-after-strike). The shape is a bare number — the streak at generate-time, the same figure the 500-threshold compares; a clean turn zeroes it, every loop starts at 0, and `0` is sent explicitly (clean ≠ unreported). It is NEVER model-facing ({§rail-accounting-private}) — headers only, the packet never carries it.
1318
-
1319
- §client-metadata **The workspace's `client` id rides the same wire.** A frontend self-identifies (e.g. `plurnk.nvim/1.4.0`) at `workspace.create({ settings: { client } })`; the engine forwards it per turn on `generate({ client })`, which only the `plurnk` provider emits (as `Plurnk-Client`). Workspace-stable and self-reported — distinct from attribution's install-grounded tags — and omitted when unset.
1268
+ §client-metadata **The workspace records which frontend opened it.** A frontend self-identifies (e.g. `@plurnk/plurnk-tui/1.4.0`) at `workspace.create({ settings: { client } })` and the daemon stores it with the workspace. It is validated on write, never forwarded to a provider, and never model-facing. Workspace-stable and self-reported — distinct from attribution's install-grounded tags — and omitted when unset.
1320
1269
 
1321
1270
  ### §provider-instantiation Provider instantiation
1322
1271
 
@@ -1367,7 +1316,7 @@ PLURNK_MODEL=gemma
1367
1316
 
1368
1317
  First path segment = provider name; rest = provider-native model id.
1369
1318
 
1370
- ### §mock-provider Mock provider (sibling fixture)
1319
+ ### Mock provider (sibling fixture)
1371
1320
 
1372
1321
  §mock-provider-mock-fixture `Mock` (exported from `@plurnk/plurnk-providers`) — intg fixture + reference implementation. `{ contextWindow, responses }` constructor; `generate` shifts from the queue. `MockResponse.assistant.ops?: PlurnkStatement[]` is a pre-parsed escape hatch the engine consumes directly when present; production providers don't expose this — and being a plugin export, this contract has no service-side `§`-ref.
1373
1322
 
@@ -1411,14 +1360,24 @@ meaning of an authored URI authority before any entry capability is exposed:
1411
1360
  | Project files | Filesystem namespace | Workspace policy | Shared live |
1412
1361
  | `worker:///...` | Empty, shared scratch | Any workspace actor | Shared live |
1413
1362
  | `worker://alice/...` | Named scratch | Any workspace actor | Snapshot source namespace into new name |
1414
- | `prompt://alice/...` | Named prompt evidence | Intrinsic scheme contract; model-read-only | Snapshot source history into new name |
1415
- | `ops:///...`, `reasoning:///...` | Current worker's turn coordinates | Immutable for every actor | Snapshot sources at identical local coordinates |
1363
+ | `ops://<worker>/<loop>/<turn>`, `reasoning://<worker>/<loop>/<turn>` | Named worker's turn history | Immutable for every actor | Snapshot sources at identical coordinates under the child's name |
1364
+ | `note://<worker>/<loop>/<turn>/<item>` | Named worker's NOTE history | Immutable for every actor | Snapshot sources at identical coordinates under the child's name |
1365
+ | `ops://<worker>/<loop>` | Named worker's loop | Immutable: what it said, or how it ended | Snapshot terminal history under the child's name |
1366
+ | `message://<worker>/<id>` | Native message admitted to the named worker | Immutable; SEND records a separate reply | Retain original addresses |
1367
+ | `log:///<loop>/<turn>/<item>/<op>` | Implicit observing worker | KILL curates the projection, not its source | Snapshot projection; explicit source addresses stay unchanged |
1368
+ | `<executor>:///<id>` | Empty, workspace output namespace | Executor stream contract | Shared live; no copied process |
1416
1369
  | `skill://recipe/...` | Installed skill name | Skill resource contract | Shared installation |
1417
1370
  | HTTP, WebSocket, executor/MCP, A2A resources | Scheme's canonical namespace | Scheme contract and workspace policy | Shared live; no copied connection |
1418
1371
 
1419
1372
  Copied bodies and log references remain verbatim. Explicit source addresses continue to name the source; only copied scratch/evidence resources' own authority becomes the child's name ({§machine-processes-entry-inheritance}).
1420
1373
 
1421
- §fs-namespace **The workspace is a mount namespace; `project_root` is the model's `/`.** Chroot semantics: host paths do not exist inside the jail, and no engine surface folds a host-absolute spelling onto a member. The root is **fixed immutably at workspace creation** (headless is forever); the namespace's mount table changes only through the declared membership overlay ({§membership}), never by re-rooting. At `project_root = /` the jail is the whole filesystem and every rule below degenerates to identity — the design's proof case, and the common benchmark topology.
1374
+ The scheme identifies the resource kind, the authority names its namespace, and
1375
+ the path identifies the resource within it. History uses worker-local loop/turn/item
1376
+ sequences; native messages and workspace outputs use opaque identifiers rather than
1377
+ pretending to be turn coordinates. `worker://<name>` addresses the actor, not a
1378
+ historical execution. No address grants ownership or access restrictions.
1379
+
1380
+ §fs-namespace **The workspace is a mount namespace; `project_root` is the model's `/`.** A namespace *names*; it does not confine. Host paths do not exist in it, and no engine surface folds a host-absolute spelling onto a member — not because a wall refuses them, but because those coordinates have no meaning here. What the model can reach is exactly the mount table, which the operator composes: a membership overlay routinely mounts a path from above the root (`../house-policy.md` is an ordinary `include` grantor, {§fs-visibility-grantors}), and it arrives named in namespace coordinates like everything else. Plurnk is therefore not a sandbox and claims no containment — confinement is the host's job; what Plurnk owns is authority, consent and audit. The root is **fixed immutably at workspace creation** (headless is forever); the mount table changes only through the declared membership overlay ({§membership}), never by re-rooting. At `project_root = /` the namespace is the whole filesystem and every rule below degenerates to identity — the design's proof case, and the common benchmark topology.
1422
1381
 
1423
1382
  §fs-namei **Resolution is namei over the mount table.** The model's CWD is permanently `/`, so `src/x.md` and `/src/x.md` are the same name — the slash rule is a corollary, never a legislated equivalence. Resolution is lexical: `.` and `..` resolve before anything touches storage (`..` is legal *during* traversal); the final name lands in the root subtree (a bare key), on a declared outside-root mount (a `../`-prefixed key — the git-style overlay), or names nothing (404 carrying the resolved form). Containment is the resolution semantics — there is no separate traversal check to forget.
1424
1383
 
@@ -1481,7 +1440,7 @@ Every fact names the canonical key, never the host root or an echo of the
1481
1440
  model's spelling. These classes let a caller distinguish a wrong address, an
1482
1441
  invalid range, read-only authority, and occupied hidden state without guessing.
1483
1442
 
1484
- §membership-read-refusal **A READ miss that is really a non-member is refused, not denied.** An exact-path READ of an in-root path that exists on disk but is not a member returns 404 `entry-not-member` — `'<key>' exists on disk but is not a member of this workspace.` — with a recovery naming the door (```` ```members (add) ```` with a `{"glob": "<path>"}` body); it never claims absence. Occupancy surfaces, content does not ({§membership}).
1443
+ §membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, with a recovery naming both doors: EDIT creates a member at the path, and ```` ```members (add) ```` with a `{"glob": "<path>"}` body admits a file that already exists. The sentence is about the address and is true whether or not a file is there: it neither claims absence nor hints at presence. Beyond the root the engine does not look at the disk at all, so two reads of `../` paths differ only in the name they echo. Inside the root occupancy is not secret ({§fs-write-nonmember}), so an exact-path READ of a path that exists on disk but is not a member says so instead — 404 `entry-not-member`, `'<key>' exists on disk but is not a member of this workspace.` Occupancy may surface there; content never does ({§membership}).
1485
1444
 
1486
1445
  §fs-world-state **The world-state harness — coverage that closes the class.** Op-outcome tests check what an op returned; the harness checks the resulting world. `WorldState.check(db)` asserts, pure-db and read-only: identity uniqueness in practice (no tuple holds two rows), the canonical fixpoint on every file-class key, channel orphan-freedom, the closed admission set (every file row's origin is Git or constraint), and sig-coherence. Generated-pick incorporation and lifecycle require filesystem/Git evidence and are covered by the composed creation matrix rather than a false pure-database proxy. The harness runs as a lifecycle-test epilogue and at every soak turn boundary, where the delta half applies: an idle turn grows the entries table by ZERO. A violation names its law and its row.
1487
1446
 
@@ -1498,13 +1457,14 @@ own a more specific operation. A stored-entry publication atomically upserts
1498
1457
  one workspace identity, metadata, and its complete channel set. Concurrent
1499
1458
  publications expose one complete result, never a mix of channels; a failed
1500
1459
  publication leaves the prior entry unchanged. Omitted attributes preserve the
1501
- existing bag. Reads observe metadata and channels in one snapshot. There is no
1460
+ existing bag. Unchanged channel representations retain their derivations;
1461
+ changed representations invalidate them and omitted channels are removed.
1462
+ Reads observe metadata and channels in one snapshot. There is no
1502
1463
  cross-scheme SQL transaction. Core's create-only publication claims the same
1503
1464
  identity atomically: an existing identity returns 409 without changing its
1504
- metadata or channels. Generated prompt IDs retry that collision; they never
1505
- upsert another prompt's contents ({§prompt-address}).
1465
+ metadata or channels.
1506
1466
 
1507
- ### §op-methods Op methods
1467
+ ### Op methods
1508
1468
 
1509
1469
  §op-methods-op-dispatch Engine operation ownership follows the public scheme contract:
1510
1470
 
@@ -1521,7 +1481,7 @@ Registration precedes loop affinity:
1521
1481
  | Registered but inactive under flag | The flag gate returns `403 scheme-unavailable`. |
1522
1482
  | Registered and active | Dispatch continues to the operation owner. |
1523
1483
 
1524
- - §op-execution-order **An admitted turn is an ordered program.** Model, client, and harness operations execute in authored order. Only an explicit disposition operation is deferred until all other admitted operations settle or establish their explicitly asynchronous work; a model turn may author it anywhere ({§disposition-anywhere}), and internal and client programs keep the same schedule. Its obligation checks and client-visible completion run last. Without a disposition, the turn settles its spawns and defaults to 102 without inventing an operation or inventory; existing cycle, no-operation, and resource rails remain effective. An observation records the resource state at its execution point; the model sees that receipt in the next packet. Exact submitted source and actual operation outcomes remain durable. Earlier successful effects survive a later operation failure; a producer requesting fail-on-error stops before subsequent operations.
1484
+ - §op-execution-order **An admitted turn is an ordered program.** Model, client, and harness operations execute in authored order. Only WAIT is deferred until all other admitted operations settle or establish their explicitly asynchronous work ({§disposition-anywhere}). The complete program then settles under {§wait-obligation-matrix}, whether or not it contains WAIT; no completion operation or inventory is invented. Existing cycle, no-operation, and resource rails remain effective. An observation records the resource state at its execution point; the model sees that receipt in the next packet. Exact submitted source and actual operation outcomes remain durable. Earlier successful effects survive a later operation failure; a producer requesting fail-on-error stops before subsequent operations.
1525
1485
 
1526
1486
  §bare-inference **BARE is isolated, synchronous retrieval over the durable child-provider policy.**
1527
1487
 
@@ -1538,11 +1498,12 @@ Registration precedes loop affinity:
1538
1498
  - §op-synchronous **Decisive operations settle before the next operation.** The dispatcher awaits each operation and its proposal resolution. Work remains in flight only when the operation's contract deliberately creates concurrency: FORK, WORK, a stream-producing execution, and streaming READ after acquisition. Such a READ first establishes its durable subscription and returns `102`; a later operation may address that live owner. Dispatching an execution before KILL does not wait for the process to finish using a resource. KILL of a worker synchronously ends its live loops before disposition checks the pending set; physical scope cleanup remains asynchronous.
1539
1499
  - §edit-execution **One authored EDIT is one mutation.** Each EDIT resolves against current resource state when dispatch reaches it, owns its proposal when gated, and records its own resulting revision. No later EDIT is prepared or applied in advance. Numeric scopes address current coordinates; an earlier EDIT may change what those numbers select. Rejection applies only to that operation, not its successful siblings.
1540
1500
  - §edit-anchor-continuity **Own EDITs preserve untouched hash targets within one program.** Core carries an anchor through exact, successfully applied EDIT splices when its line survives unchanged, even if its ordinal or neighborhood changes. Scoped entry KILL uses the same deletion path. Target-line replacement or deletion invalidates that binding. Continuity is private to the admitted program and canonical resource/channel; it is not a new published anchor format. The complete normalized line content must match the expected result of the preceding recorded EDIT, otherwise retained bindings are discarded and ordinary current-state validation applies. Reviewer replacement and results without an applied EDIT receipt do not carry bindings forward. Normalization is the same line-content representation used by READ and line hashing; file-write revision checks remain independent. No approximate text matching is used. Lowered coordinates retain a current-anchor precondition at the mutation owner; ambiguous matches and concurrent changes remain collisions.
1501
+ - §anchor-offset **An anchor offset is tolerated, never taught (#749).** A line mark may carry an offset from its anchor (`@abcde+1`, `@abcde-2`), and a bare `+N` after an anchor counts from that anchor (`<@abcde,+1>`). The anchor resolves as usual and the offset is added; a result before line 1 is an invalid mark, and past the end is the ordinary range refusal. Continuity and current-anchor preconditions check the anchor's own line. No teaching text, scope table or receipt mentions offsets; `plurnk.md` keeps its two anchor forms. A bare `+N` with no anchor before it is refused as before.
1541
1502
  - §edit-batch **One compound operation may require atomic splices.** The scheme's `editBatch` primitive validates all supplied numeric edits against one snapshot and commits one revision or none. Core supplies one statement for an authored EDIT; same-resource MOVE can supply multiple splices as one operation. This primitive does not group separate authored operations. Its replacement, insertion, conflict, and receipt rules remain owned by the shared Slicer.
1542
1503
  - §edit-batch-receipt **A refusal describes its own unapplied work.** An anchor collision lists every distinct unresolved anchor in that EDIT, including both range endpoints, in `unresolvedAnchors` (`anchor`, `kind: missing | ambiguous`, and matching `lines` when ambiguous). Missing is not proof of earlier validity or subsequent change. It carries `editCount: 1`, `applied: 0`, and recovery directing a READ for current coordinates; it makes no claim about other operations. A refused compound splice batch lists all conflicting pairs in `conflicts`, non-conflicting regions in `cleanRegions`, its first pair in `conflictingRegions`, and its own `editCount` and `applied: 0`.
1543
1504
  - §edit-batch-merges **Normalizations require evidence and a receipt.** An EDIT body carrying only this resource's published `@xxxxx L:` prefixes is stripped when those prefixes verify against current anchors or this worker's preserved READ receipts (`rendered-prefix-stripped`); otherwise it remains literal content (`rendered-prefix-unverified`). Within a single atomic splice batch, the Slicer can deduplicate identical regions/bodies, concatenate same-boundary insertions, assign a shared endpoint to the sole body reproducing that line, or relocate an inner change when its original content occurs exactly once in the outer body. An already-applied inner body can be dropped. Unevidenced overlap remains a collision. These batch resolutions never reinterpret separate authored EDITs. Applied normalizations carry their exact merge facts and a notice; receipts describe only the applied effects.
1544
1505
 
1545
- ### §orchestration Cross-scheme orchestration
1506
+ ### Cross-scheme orchestration
1546
1507
 
1547
1508
  Core owns same- and cross-scheme transfers under {§copy} and {§move}; handlers
1548
1509
  provide the underlying resource operations. Each operand independently selects
@@ -1550,16 +1511,40 @@ a resource, channel, and optional text scope ({§transfer-resource-selections}).
1550
1511
  Source acquisition follows {§universal-read-composition}; landed mutation
1551
1512
  effects follow {§edit-result-copy-move-effects}.
1552
1513
 
1553
- ### §send-dispatch SEND dispatch (a message to a recipient)
1514
+ ### SEND dispatch (a message to a recipient)
1554
1515
 
1555
- A recipient SEND (non-null path — {§turn-disposition}) routes to the scheme's
1556
- `send`: the body is the message — a WebSocket frame, exec stdin, an HTTP POST, an A2A
1557
- message, a worker's next prompt. TASK never reaches a scheme: it controls the
1558
- turn ({§send}). Cancelling a stream and deleting an entry are KILL ({§stream}, {§move}).
1516
+ Targetless and exact-message SENDs follow the reply accounting at
1517
+ {§send-response-receipt}. Other directed SENDs route to the recipient scheme's
1518
+ `send`: the body is the message — a WebSocket frame, exec stdin, an HTTP POST,
1519
+ an A2A message, or new work for a worker.
1559
1520
 
1560
- §send-dispatch-entry-schemes-501 An entry-bearing scheme carries no messages: a recipient SEND aimed at one returns 501.
1521
+ §send-dispatch-entry-schemes-501 A SEND aimed at a resource entry, rather than a
1522
+ message or actor endpoint, returns 501. Its recovery distinguishes replying to
1523
+ Open Messages from sending new work to a worker, without assuming either intent.
1561
1524
 
1562
- Null-path SEND is broadcast ({§send}), engine-handled.
1525
+ #### §send-resource-attachments Explicit message attachments
1526
+
1527
+ Targetless replies, worker messages, and A2A messages accept
1528
+ `[{"attachments":["report.pdf","worker://alice/result.json"]}]` on SEND.
1529
+ The body remains the authored message, not an attachment envelope.
1530
+
1531
+ | Boundary | Contract |
1532
+ |---|---|
1533
+ | Selection | An ordered array of exact resource/channel addresses; no implicit export, glob expansion, or Markdown-link interpretation. |
1534
+ | Acquisition | The same source selection and representation preparation as COPY, under ordinary READ capability admission; acquire every source before delivering the message. A failed source produces its normal failure and delivers nothing. |
1535
+ | Snapshot | Preserve the selected bytes, media type, name, and source address at SEND time. Later source mutation, deletion, or log curation cannot alter the delivered content. |
1536
+ | Receipt | Safe attachment descriptors identify immutable content; binary payloads do not enter ordinary log text. |
1537
+ | Ownership | Message recipients opt into this option. HTTP headers and executor stdin retain their own metadata contracts. |
1538
+ | Arrival | Publish attachments as ordinary typed resources and link them from the inbound SEND. Arrival alone does not inject native media; READ does. |
1539
+
1540
+ #### §message-envelope-evidence Durable message evidence
1541
+
1542
+ The ordinary inbox retains an optional transport envelope alongside the
1543
+ model-facing body and attachments. Exterior adapters own its protocol shape;
1544
+ Core preserves it without interpreting protocol fields. History reads this
1545
+ durable evidence, not a curated text projection. Accepted interaction answers
1546
+ retain their envelope before waking the waiting operation; rejected answers
1547
+ create no message evidence.
1563
1548
 
1564
1549
  ### §scheme-surface Consumption surface
1565
1550
 
@@ -1634,9 +1619,9 @@ Handler authority, discovery, projection identity, and failures follow
1634
1619
  persistence, packet accounting ({§tokenomics-agnostic-ruler}), and subscriptions
1635
1620
  ({§subscriptions}); handlers do not.
1636
1621
 
1637
- ### §mimetype-surface Consumption surface
1622
+ ### Consumption surface
1638
1623
 
1639
- plurnk-service is mimetype-illiterate. Engine hands channel content + mimetype label to `Mimetypes.process({content, hint})`; the manifest build uses `result.totalLines` for each channel's `lines`. Content reaches the model on READ, not as a rendered preview.
1624
+ plurnk-service is mimetype-illiterate. A channel's `lines` is stored when its content is written, so the catalog reads no bodies and calls no handler; `Mimetypes.process({content, hint})` serves search derivation ({§persistent-search-index}) and parse-issue probes. Content reaches the model on READ, not as a rendered preview.
1640
1625
 
1641
1626
  §mimetype-owned-lifecycle `Daemon` owns and disposes the `Mimetypes` instance
1642
1627
  it constructs. A constructor-injected instance remains caller-owned. Shutdown
@@ -1664,7 +1649,7 @@ model-independent ruler for stored/catalog weights and the model-facing curation
1664
1649
  confined to provider-owned physical capacity assessment
1665
1650
  ({§tokenomics-context-envelope-admission}).
1666
1651
 
1667
- **Conformance.** Mimetype-specific behavioral tests live in each handler's own surface. plurnk-service intg covers integration: the engine routes through `Mimetypes.process` with the right hint and the catalog reflects `totalLines`; tests use auto-discovery (production handler set); a custom-handler test injects a stub `BaseHandler` via `loader + discovery`.
1652
+ **Conformance.** Mimetype-specific behavioral tests live in each handler's own surface. plurnk-service intg covers integration: the engine routes through `Mimetypes.process` with the right hint and the catalog reflects the stored line count; tests use auto-discovery (production handler set); a custom-handler test injects a stub `BaseHandler` via `loader + discovery`.
1668
1653
 
1669
1654
  ## §persistent-search-index Search indexing
1670
1655
 
@@ -1682,6 +1667,15 @@ empty setting excludes nothing, and the first match is the observable reason.
1682
1667
  | Other-scheme channel | Always eligible; its pathname is a resource identity. |
1683
1668
  | Log projection | Always eligible; it has no repository-path membership. |
1684
1669
 
1670
+ §search-size-bound Every search subject, whatever its scheme, is also bounded
1671
+ by size when the operator sets one: a body longer than
1672
+ `PLURNK_SERVICE_SEARCH_MAX_BYTES` (default empty = unbounded) is `excluded` with the reason `larger than N bytes`, before
1673
+ its body is read. It is neither parsed for symbols nor full-text indexed; READ,
1674
+ FIND by path, and membership are unaffected. The reason joins the derivation
1675
+ identity, so changing the bound re-derives the affected bodies and retention
1676
+ collects what they leave. Origin (#729): the dogfood workspaces indexed 29
1677
+ tokenizer vocabularies (up to 31 MB each) as full text.
1678
+
1685
1679
  A match produces the `excluded` derivation disposition and suppresses graph
1686
1680
  and FTS while leaving the stored channel and direct READ unchanged. The
1687
1681
  same reason participates in the derivation hash and is surfaced by diagnostics
@@ -1714,7 +1708,7 @@ operator knobs in `.env.defaults`. Search indexing performs no inference.
1714
1708
 
1715
1709
  ## §channels Channel Topology
1716
1710
 
1717
- §channels-channels-append-only Every entry has named channels. **Channels are append-only content stores** keyed by `(entry_id, name)`. Schemes write content; the engine reads at turn boundaries; mimetype handlers interpret.
1711
+ §channels-entry-name-key Every entry has named channels: **content stores keyed by `(entry_id, name)`**, one row per name. Schemes write content — appending to a channel, replacing it, or deleting it; mimetype handlers interpret it.
1718
1712
 
1719
1713
  ### §per-entry-channels Per-entry channels
1720
1714
 
@@ -1753,17 +1747,17 @@ Rules:
1753
1747
  | URI | Channel |
1754
1748
  | ------------------------------------ | ------------------------------------ |
1755
1749
  | `worker:///france/capital` | body (default) |
1756
- | `sh:///1/1/2/sh#stdout` | stdout |
1757
- | `sh:///1/1/2/sh#stderr` | stderr |
1750
+ | `sh:///a3b7c921#stdout` | stdout |
1751
+ | `sh:///a3b7c921#stderr` | stderr |
1758
1752
  | `https://feed.example/y#body` | body |
1759
- | `log:///N/T/A` | (no channel concept; atomic log row) |
1753
+ | `log:///1/2/3/READ` | (no channel concept; atomic log row) |
1760
1754
 
1761
1755
  Op implications:
1762
1756
 
1763
1757
  - EDIT to undeclared channel → 404; read-only channel → 405.
1764
1758
  - COPY/MOVE source and destination fragments independently select channels.
1765
1759
 
1766
- Client-interface target parameters carry fragments inline (`{ target: "sh:///1/1/2/sh#stderr" }`).
1760
+ Client-interface target parameters carry fragments inline (`{ target: "sh:///a3b7c921#stderr" }`).
1767
1761
 
1768
1762
  **Wire rendering: default channel is path-only.** A rendered target omits `#channel` when channel matches `defaultChannel`. Single-channel entries render path-only; multi-channel entries render the default path-only and only non-default carries `#name`.
1769
1763
 
@@ -1802,7 +1796,7 @@ Model uses state to anticipate growth between turns. Clients use state for UI (s
1802
1796
 
1803
1797
  ---
1804
1798
 
1805
- ## §op Op Surface
1799
+ ## Op Surface
1806
1800
 
1807
1801
  Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkStatement`. Engine dispatches by `op`; scheme implements per author contract ({§scheme}).
1808
1802
 
@@ -1947,6 +1941,7 @@ READ is the one fan-out core performs ({§read-fan-out}).
1947
1941
  when that differs from the channel's own mimetype the result names the
1948
1942
  channel's as `sourceMimetype`, so a consumer can still run the channel's
1949
1943
  handlers over a whole-resource `<1,-1>` read.
1944
+ - §log-range-miss-names-stream A 416 on a log execution item is the range twin of its channel miss ({§log-channel-miss-names-stream}): the coordinate addresses the row's invocation (its authored call body, often empty or one line) while the execution's output stays readable at the stream address the row records. When that stream link exists, the 416 gains it as `stream`, the detail appends where the command's streams live, and `recovery` is `READ <stream> for the command's stream`, whether the invocation's extent is empty or merely shorter than the range (#759). A 416 on a row with no recorded stream stays byte-identical to the generic slicer's.
1950
1945
  - §read-pattern **A pattern selects the lines a READ renders.** With a heading
1951
1946
  matcher ({§matcher-option} in the contracts SPEC) an exact-target READ stays a
1952
1947
  READ: the matcher runs over the channel's text line by line — a regex anchors
@@ -1983,13 +1978,14 @@ READ is the one fan-out core performs ({§read-fan-out}).
1983
1978
  resources, not lines, so that READ dispatches as the FIND survey. Operator,
1984
1979
  2026-09-13: "give it what it asked for" — a model that asked to read the pantry
1985
1980
  looped five turns on the catalog it was handed instead.
1986
- - §read-bytes A binary channel with no readable projection, and the `#bytes` view of
1981
+ - §read-bytes A binary channel, and the `#bytes` view of
1987
1982
  any resource whose scheme supplies bytes, reads as the source bytes one hexadecimal
1988
1983
  octet per line: coordinate = line = byte, so `<a,b>` selects bytes, the markerless
1989
- default is the same `<1,16>`, `<1,-1>` is the whole resource, and the extent carries
1984
+ default is the shared first page ({§markerless-first-page}), `<1,-1>` is the whole resource, and the extent carries
1990
1985
  `unit: "byte"`. The result keeps the source mimetype and names `projection: "hex"`;
1991
1986
  anchors do not exist there (400). Bytes are read from the source at READ time, sized
1992
- then windowed, never stored: `file:` supplies them from the member on disk, and a
1987
+ then windowed: `file:` supplies them from the member on disk, DB-backed schemes
1988
+ recover their stored bytes under {§binary-parity}, and a
1993
1989
  scheme that keeps no bytes answers 501 `bytes-unavailable` for `#bytes` and 415 for a
1994
1990
  binary channel, as before. An execution whose target is a file member already runs the
1995
1991
  bytes on disk. Byte selection affects only this hexadecimal projection: when the
@@ -2017,8 +2013,11 @@ READ is the one fan-out core performs ({§read-fan-out}).
2017
2013
  window is preserved, and the whole spliced result is re-written through the proposal gate. A binary
2018
2014
  **lives in a DB entry** as its bytes base64 in the channel's TEXT content; the same READ, byte range,
2019
2015
  and COPY/MOVE recover them through a byte source synthesized from that content, so a File member and a
2020
- `worker://` entry hold and yield a binary identically. This supersedes the older blanket refusal (#140)
2021
- for both the file and the entry case. Native image/PDF attachment facts come from the configured
2016
+ `worker://` entry hold and yield a binary identically. An empty binary channel represents
2017
+ zero bytes, not an unsupported format; whole COPY/MOVE preserves it. Failed acquisition
2018
+ is not an empty success: its producer outcome remains authoritative for READ and transfer.
2019
+ This supersedes the older blanket refusal (#140)
2020
+ for both the file and the entry case. Native image/PDF/audio attachment facts come from the configured
2022
2021
  mimetype handler over original bytes, whether supplied by a file or stored channel
2023
2022
  ({§packet-attachment-parts}); the hexadecimal view remains available. The exceptions are narrow and
2024
2023
  defined, each a clear receipt rather than a dead end: a binary region addressed by a **textual anchor**
@@ -2051,30 +2050,23 @@ same transitions the dispatcher's atomic curation event makes, without the row.
2051
2050
  | Surface | Contract |
2052
2051
  |---|---|
2053
2052
  | Evidence | Original provider reasoning remains verbatim in immutable model-call responses and admitted packets. Resource and log operations never rewrite it. Only an admitted response, or the final exhausted emission attempt, produces a model reasoning source; missing provider reasoning creates no substitute. A non-model producer may record its own authored rationale under {§turn-source-resources}. |
2054
- | Resource | `reasoning:///<loop>/<turn>` is immutable text/plain source belonging to the current worker's turn under {§turn-source-resources}. Every actor may READ, FIND, search and COPY from it; none may EDIT, KILL, COPY into or MOVE it. |
2053
+ | Resource | `reasoning://<worker>/<loop>/<turn>` is immutable text/plain source belonging to the named workspace worker's turn under {§turn-source-resources}. Every workspace actor may READ, FIND, search and COPY from it; none may EDIT, KILL, COPY into or MOVE it. |
2055
2054
  | Delivery | Initialization READs its own authored rationale under {§reasoning-initial-read}. Further observations require deliberate READs. The selected model reasoning source is stored before its OPs execute, so an ordinary READ of the current turn resolves immediately and is visible in subsequent packets. Every READ retains its authored scope and ordinary range metadata, without edit anchors. |
2056
2055
  | Curation | Scoped log KILL suppresses receipt lines; whole log KILL retires the receipt. Neither affects the source. Explicit log READs retain ordinary curation anchors. A mutable working copy requires ordinary COPY into an editable resource. |
2057
- | Lifecycle | Restart retains sources and observations. FORK snapshots sources at the same local coordinates and receipts with independent curation. No curation or lifecycle event automatically READs model reasoning. A turn the provider left without reasoning reads empty; future and foreign coordinates return the ordinary missing result ({§turn-source-resources}). |
2056
+ | Lifecycle | Restart retains sources and observations. FORK snapshots sources under the child's name at the same loop/turn coordinates and receipts with independent curation. No curation or lifecycle event automatically READs model reasoning. A turn the provider left without reasoning reads empty; absent workers and turns return the ordinary missing result ({§turn-source-resources}). |
2058
2057
  | Client | Standard live reasoning events and replay retain original provider reasoning; working resources and READ receipts never substitute for or replay that stream. |
2059
2058
 
2060
2059
  ### §reasoning-initial-read Initial reasoning observation
2061
2060
 
2062
- The real initialization turn records a short `_plurnk`-authored rationale before
2063
- executing its program. That program READs its own reasoning and its own persisted
2064
- ops before TASK; the Active Prompt arrives as its `prompt` row ({§prompt-entry}),
2065
- never as a second READ. The rationale identifies its harness origin and carries
2066
- exactly one `Note:` line — `Note: Prior reasoning can be searched with the pattern
2067
- filters.` (operator's words, 2026-09-13) — and the reasoning READ is the pattern
2068
- read `READ (reasoning:///L/T) ^Note:.* <!-- pluck notes from this turn's reasoning -->`
2069
- ({§naked-pattern} in the contracts SPEC), so the first model packet shows the
2070
- maneuver working rather than described: only the note lands. The model's own
2071
- coordinate is inferable from the `## Worker` block below the log
2072
- ({§packet-current-turn}), so the note teaches nothing the packet already says
2073
- (operator, 2026-09-12: "Recursive Reasoning" — mark what must survive `Note:`,
2074
- pluck it, and let the rest of the reasoning go). Each resolves through ordinary
2075
- READ dispatch.
2061
+ The initialization turn records a short `_plurnk`-authored rationale containing
2062
+ a fenced NOTE. The shared reasoning extractor ({§reasoning-notes}) executes that
2063
+ NOTE through ordinary dispatch, creating its log item and immutable source.
2064
+ The program begins with its own NOTE and READs its reasoning and persisted ops,
2065
+ demonstrating both NOTE placements and their ordinary results. The initial message arrives separately as an
2066
+ inbound SEND ({§message-arrival}). Neither initialization nor later turns
2067
+ manufacture a task inventory.
2076
2068
  `PLURNK_REASONING_VIEW_LINES` (default `-1`, alias-scoped) selects this one READ's
2077
- scope: `0` omits it, `-1` leaves the pattern unbounded, and a positive integer
2069
+ scope: `0` omits it, `-1` reads the complete rationale, and a positive integer
2078
2070
  bounds it to the first N lines. Source retention, deliberate READs, and client
2079
2071
  streaming are independent. No later turn automatically requests reasoning.
2080
2072
 
@@ -2118,18 +2110,66 @@ The `## Log` section is a sequence of ordinary Markdown records separated by one
2118
2110
  <coordinate-prefixed body lines when visible>
2119
2111
  ```
2120
2112
 
2121
- The H3 is the row's complete model-facing identity and canonical READ target; metadata never duplicates `path` or `op`. The following line is one strict JSON object: every receipt puts `target` first and `aside` second when present; all remaining members use stable alphabetical order. Absent fields are not invented. Every physical body line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, so source text cannot create a record boundary. The section contains records only, with no leading prose or enclosing fence.
2113
+ The H3 is the row's complete model-facing identity and canonical READ address; metadata never repeats that identity or its operation. The following line is one strict JSON object: addressed operands ({§log-address-metadata}) precede `aside`, then all remaining members use stable alphabetical order. Absent fields are not invented. Every physical body line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, so source text cannot create a record boundary. The section contains records only, with no leading prose or enclosing fence.
2114
+
2115
+ §log-address-metadata **Addresses name their relationship, not the row's producer.**
2116
+
2117
+ | Metadata | Meaning | Order |
2118
+ |---|---|---|
2119
+ | `path` | The operation's addressed operand, matching `OP (path)`: read resource, mutation subject, message recipient, or executor operand. Explicit and automatic READs use the same field. Pathless operations omit it. | First |
2120
+ | `from`, `to` | COPY/MOVE's two operand selections, each retaining its optional scope; neither replaces actor attribution or is repeated as `path`. | First, in that order |
2121
+ | `stream` | An executor invocation's separately created output address, never a READ's alternative spelling of `path`. | Remaining facts |
2122
+ | `resource` | A distinct returned resource under {§operation-resource-receipt}. | Remaining facts |
2123
+
2124
+ Nested mutation effects and delivered attachments name their resource with `path`.
2125
+ These packet spellings do not rename the submitted AST, durable operation results,
2126
+ or client protocol fields. Invocation correlation remains on the subscription and
2127
+ its publication identity; an automatic stream READ does not copy the invocation's
2128
+ log address into its `source`. Actual actor/subsystem attribution remains governed
2129
+ by {§env-delta-attribution}.
2122
2130
 
2123
- Coordinate-prefixed lines are the text currently in context; a metadata-only row contributes no text body. A partially trimmed row carries `"folded":["<scope>",...]`; coordinate gaps expose omissions without renumbering. A bounded projection carries `"chunk":"showing <selected> of <complete>"` in metadata. Complete-line extents use inclusive two-coordinate regions; a cut inside a line uses four-coordinate, start-inclusive and end-exclusive regions with 1-based Unicode code-point columns.
2131
+ Coordinate-prefixed lines are the text currently in context; a metadata-only row contributes no text body. Selection, preview, and curation metadata follow {§packet-extent-metadata}; coordinate gaps expose omissions without renumbering.
2132
+
2133
+ §packet-extent-metadata **One scope notation, distinct coordinate owners.**
2134
+
2135
+ | Field | Coordinate owner | Representation |
2136
+ |---|---|---|
2137
+ | `range` | The resource addressed by a successful READ/FIND | `<first,last> of N lines/resources/match locations/bytes`; singleton scopes use `<first>`. A complete dense selection reduces to `N units`; an empty selection from a nonempty extent is `none of N units`. |
2138
+ | `range` for exact text | The addressed text resource | `<startLine,startColumn,endLine,endColumn>`; no invented available extent. |
2139
+ | `preview` | The retained receipt body | Only when displayed incompletely: selected scope(s) `of N lines`, or exact selected region `of` complete region for an in-line cut. Replaces the body's otherwise redundant `lines` count. |
2140
+ | `trimmed` | The receipt's original physical body lines | Array of deliberately removed `<scope>`s on a partially visible row; initial suppression is not curation. |
2141
+ | `effect` | The mutation's source and landed revisions | Resolved `<source> -> <result>`; counts and complete-resource extent remain separate facts. |
2142
+
2143
+ Scopes use the existing inclusive line/item/byte coordinates or start-inclusive,
2144
+ end-exclusive Unicode-code-point text regions ({§text-scope-semantics}). Sparse
2145
+ retrieval ranges are enclosing spans; body ordinals and matcher counts retain
2146
+ the gaps, and a sparse span covering both endpoints is not abbreviated as a
2147
+ complete acquisition. Sparse previews list their selected contiguous runs.
2148
+ Retrieval `range` records acquisition, not subsequent visibility: KILL changes
2149
+ the log projection, never the original source selection. A READ's source line
2150
+ numbers and its receipt's body-relative curation coordinates remain distinct
2151
+ ({§log-kill-scope}). Byte ranges describe the hex selection, not native-media
2152
+ cropping ({§packet-attachment-parts}).
2153
+
2154
+ Successful retrieval metadata omits requested coordinates; durable results and
2155
+ submitted programs retain them. Failed selections keep requested coordinates
2156
+ and available extent in their owning Problem. Projection never parses its
2157
+ display strings to recover typed facts. A hidden body has no `preview`; a
2158
+ complete non-retrieval body retains `lines` where no other field supplies its
2159
+ navigable extent. None of these spellings changes acquisition, delivery,
2160
+ curation, admission, or immutable evidence.
2124
2161
 
2125
2162
  Field absence carries defaults: `origin` is omitted for the owning model, `source` for the owning worker, and `status` for a routine 200. Dispositions always carry their lifecycle status, SEND its delivery status, KILL keeps an explicit 200, and every non-200 stays explicit. A present authored aside appears as `aside`. Every row's accounting follows {§packet-token-accounting}.
2126
2163
 
2164
+ - §operation-resource-receipt A result's nonempty `resource` address remains visible in receipt metadata when distinct from its `path` and `stream`. It identifies returned material without replacing the addressed operand or injecting that material into context; ordinary READ acquires it.
2127
2165
  - §packet-attachment-parts A successful READ of an attachable resource carries projection facts with its
2128
2166
  result ({§mimetype-projection-facts}): an image ({§mimetype-image}) as
2129
2167
  `image: { mimetype, width, height, bytes }`, a PDF ({§mimetype-pdf-facts}) as
2130
2168
  `document: { mimetype, pages, bytes }` (`pages` null when the page tree is unreadable; the
2131
- attachment then weighs by bytes and carries no page count). READ snapshots complete source bytes through
2132
- the scheme's byte supplier or ordinary stored binary channel ({§binary-parity}); the text/hex projection
2169
+ attachment then weighs by bytes and carries no page count), or audio ({§mimetype-audio-facts}) as
2170
+ `audio: { mimetype, duration, bytes }` (`duration` in seconds, null when unknown). READ snapshots complete source bytes through
2171
+ the scheme's byte supplier or ordinary stored binary channel ({§binary-parity}), checking
2172
+ {§mimetype-binary-input} before loading the native snapshot; the text/hex projection
2133
2173
  and native observation use those same bytes. Immutable content-addressed `native_contents` stores each
2134
2174
  byte sequence once; the result's `nativeContentHash`, enforced by the log's foreign key, identifies it.
2135
2175
  This is retained evidence, not a separate visibility or delivery lifecycle. Source mutation/deletion
@@ -2140,12 +2180,13 @@ Field absence carries defaults: `origin` is omitted for the owning model, `sourc
2140
2180
  suppresses the complete native part under {§context-output-admission}. Unsupported routes receive only the
2141
2181
  text projection and no native charge; switching back to a compatible route exposes still-retained media.
2142
2182
  Each included part contributes `tokensAttachment` within `logTokens`: `ceil(width × height / 750)` for an
2143
- image, `pages × 1500` for a document, or `ceil(bytes / 4)` when its page count is unknown. Byte ranges select
2183
+ image, `pages × 1500` for a document, `ceil(duration × 32)` for audio, or `ceil(bytes / 4)` when page count
2184
+ or duration is unknown. Byte ranges select
2144
2185
  hexadecimal text, never crop the native resource. Retries reuse the frozen request; model-call evidence
2145
2186
  records the exact READ coordinates sent without controlling retention. Missing immutable bytes are an
2146
2187
  internal integrity failure, never silently dropped content. No ejection message or permanent teaching is
2147
2188
  added. These stable curation weights are not provider-token measurements ({§tokenomics-render-weight-budget}).
2148
- - §packet-token-accounting Every row reports one `logTokens` charge: its complete materialized H3, metadata, visible body, and selected native attachment. The completed record is measured to a fixed point, including the accounting field itself. No `tokensBody`, `tokensMetadata`, or `tokensActive` field is serialized. Hidden text is not charged; metadata-only rows still have a reclaimable charge. Source/FIND-item `tokens` measure source content, not the observation's context footprint. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page differs. All use stable curation weights, not provider tokens or dollars. Native component accounting follows {§packet-attachment-parts}; ordinary addressability and truthful errors follow {§log-wire-format} and {§log-wire-format}.
2189
+ - §packet-token-accounting Every row reports one `logTokens` charge: its complete materialized H3, metadata, visible body, and selected native attachment. The completed record is measured to a fixed point, including the accounting field itself. No `tokensBody`, `tokensMetadata`, or `tokensActive` field is serialized. Hidden text is not charged; metadata-only rows still have a reclaimable charge. Source/FIND-item `tokens` measure source content, not the observation's context footprint. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page differs. All use stable curation weights, not provider tokens or dollars. Native component accounting follows {§packet-attachment-parts}; ordinary addressability and truthful errors follow {§log-wire-format}.
2149
2190
 
2150
2191
  ### §retrieval-packet-metadata READ/FIND packet metadata
2151
2192
 
@@ -2153,33 +2194,41 @@ The packet projects one actionable owner for each retrieval fact:
2153
2194
 
2154
2195
  | Result mode | Extent | Result-body evidence | Additional aggregate fact |
2155
2196
  |---|---|---|---|
2156
- | line READ | compact `line` range | none | none |
2157
- | exact-coordinate READ | none | top-level `region` | none |
2197
+ | line READ | `range` in line scopes | none | none |
2198
+ | exact-coordinate READ | `range` in exact text coordinates | none | none |
2158
2199
  | READ-shaped materialization notice | none | none | generic body `lines` |
2159
- | catalog/path FIND | compact `resource` range | none | none |
2160
- | broad matcher FIND | compact `resource` range | per-resource match-location counts; a resource with exactly one match also carries that match's `locator`/`region` | nonzero complete `matchLocationCount` |
2161
- | exact matcher FIND | compact `matchLocation` range | each row's locator/region; a regex or glob row also carries `matched`, the matched text | none |
2162
- | pattern READ ({§read-pattern}) | compact `line` range over the physical lines | the selected lines with their ordinals and anchors | `matcher` and `matched`, the selected line count |
2200
+ | catalog/path FIND | `range` in resources | none | none |
2201
+ | broad matcher FIND | `range` in resources | per-resource match-location counts; a resource with exactly one match also carries that match's `locator`/`region` | nonzero complete `matchLocationCount` |
2202
+ | exact matcher FIND | `range` in match locations | each row's locator/region; a regex or glob row also carries `matched`, the matched text | none |
2203
+ | pattern READ ({§read-pattern}) | `range` over the physical lines | the selected lines with their ordinals and anchors | `matcher` and `matched`, the selected line count |
2163
2204
 
2164
2205
  Any row whose statement carried a heading pattern ({§matcher-option}) names it as
2165
2206
  `matcher`, and a pattern mutation ({§edit-pattern}, {§kill-pattern},
2166
2207
  {§copy-move-pattern}) carries its `matched` count beside its receipt, so a
2167
2208
  digest can show what a pattern selected and how much it touched.
2168
2209
 
2169
- The compact range is `{ unit, total, requested: [first,last], returned?:
2170
- [first,last] }` ({§range-extent}); empty results omit `returned`. An empty result
2210
+ The packet formats the typed {§range-extent} and {§text-region} facts under
2211
+ {§packet-extent-metadata}; the operation result retains its structured facts.
2212
+ An empty result
2171
2213
  set satisfies any well-formed page: zero matches is the answer, a 200 with no items,
2172
2214
  never a 416 (#425 F9). Transparent
2173
2215
  coordinates let the model determine whether more material exists and choose
2174
2216
  its own next request, so packet metadata never prescribes `next`, `complete`,
2175
2217
  or `all`. FIND range cardinality replaces top-level `items`, `lines`, and
2176
2218
  `matchingPathCount`; line READ likewise omits the rendered-body `lines` count
2177
- and its internally resolved whole-line region. Exact READ retains only its
2178
- region. A failed retrieval's Problem owns its range extension rather than
2179
- repeating it at top level. Generic `tokens` always weighs the rendered body;
2219
+ and its internally resolved whole-line region. Exact READ formats its region
2220
+ as `range`. A failed retrieval's Problem owns its range extension rather than
2221
+ repeating it at top level. `logTokens` weighs the complete rendered record
2222
+ under {§packet-token-accounting};
2180
2223
  generic body `lines` remains available on READ-shaped materialization notices
2181
2224
  that have no retrieval extent. FIND content weights follow {§log-wire-format};
2182
- ordinary bounded bodies expose their displayed and complete chunk extents there.
2225
+ ordinary bounded bodies expose their displayed and complete extents as `preview`
2226
+ under {§packet-extent-metadata}.
2227
+
2228
+ §read-past-end A line READ whose range starts past the end of nonempty content is
2229
+ answered like an empty FIND page: with no lines and its extent (`none of N lines`), not a 416; a
2230
+ single line past the end, a reversed range, empty content, a command's log row
2231
+ ({§log-range-miss-names-stream}) and every write keep their refusal (#759).
2183
2232
 
2184
2233
  ### §turn-ops-entry The admitted turn program
2185
2234
 
@@ -2189,17 +2238,18 @@ ordinary bounded bodies expose their displayed and complete chunk extents there.
2189
2238
 
2190
2239
  | Surface | Contract |
2191
2240
  |---|---|
2192
- | Identity | `ops:///<loop>/<turn>` and `reasoning:///<loop>/<turn>` resolve against the current worker's durable loop and turn sequences. Authorities are invalid; there is no cross-worker alias or access policy. |
2193
- | Source | `ops` is exact admitted `text/vnd.plurnk`; `reasoning` is `text/plain` containing the selected original provider reasoning or a non-model producer's authored rationale. Producer identity comes from the owning turn; a harness rationale is not provider evidence. The turn decides existence and the source decides content: a turn that exists but has no source of that kind reads as the ordinary empty resource (204, empty body), never a fabricated one; a coordinate whose turn does not exist is 404. Emptiness over absence, so `reasoning:///L/T` is a stable coordinate for every turn that happened. |
2194
- | Retention | One immutable source of each kind per turn. An optional inference-call link records provenance. Source removal follows deletion of its owning turn, never log curation. |
2195
- | Operations | Ordinary scoped READ, FIND, content search and COPY from source. READ returns data and never executes it. Sources are read-only for every actor and have no edit hashes. |
2241
+ | Identity | `ops://<worker>/<loop>/<turn>`, `reasoning://<worker>/<loop>/<turn>`, and `note://<worker>/<loop>/<turn>/<item>` name a worker in the current workspace and its durable coordinates. A note's item is its dispatched NOTE ordinal. The worker authority is required and case-sensitive; userinfo, ports, and queries are invalid. Source identity never depends on the reading worker. `log:///` remains local; READ, FIND and KILL reject log authorities, userinfo, ports and queries with 400, never substitute the caller's log. |
2242
+ | Source | `ops` is exact admitted `text/vnd.plurnk`; `reasoning` is `text/plain` containing the selected original provider reasoning or a non-model producer's authored rationale. Producer identity comes from the owning turn; a harness rationale is not provider evidence. The turn decides existence and the source decides content: a turn that exists but has no source of that kind reads as the ordinary empty resource (204, empty body), never a fabricated one; a worker or turn that does not exist is 404. |
2243
+ | Notes | Each dispatched NOTE stores its exact literal body as an immutable `text/plain` source and returns its worker-qualified address. There may be multiple notes in a turn, from reasoning, content, or another producer. A missing note is 404, not an empty invented note. Sharing its URI uses ordinary SEND; the receiver deliberately READs it. NOTE itself sends no ambient update. |
2244
+ | Retention | One ops source and one reasoning source per turn; one note source per NOTE ordinal. An optional inference-call link records provenance. Source removal follows deletion of its owning turn, never log curation. |
2245
+ | Operations | Ordinary scoped READ, FIND, content search and COPY from any named worker's source within the workspace. FIND accepts authority and path patterns, retaining complete worker-qualified identities in results and folder selectors. READ returns data and never executes it. Sources are read-only for every actor and have no edit hashes. |
2196
2246
  | Index | Source text uses the existing derivation, FTS and graph machinery; only its derivation attachment is replaceable. |
2197
- | FORK | Sources copy with the inherited turns at identical local coordinates. Branch receipt curation is independent; neither branch can rewrite source evidence. |
2247
+ | FORK | Sources copy with the inherited turns at identical loop/turn/item coordinates under the fork's own authority. Bytes and embedded source references are preserved verbatim; an explicit reference still names its original worker. Branch receipt curation is independent; neither branch can rewrite source evidence. |
2198
2248
  | Forensics | Digest assistant artifacts read source directly, independently of receipt presence or curation. Original provider responses retain all attempts and opaque fields separately. |
2199
2249
 
2200
2250
  §rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, the canonical model-facing `/attempt` leaf, and the exact latest rejected response. The packet does not duplicate that identity as `kind` metadata. It is born durably body-suppressed and projected visibly only in the informed recovery packet; every other rejected attempt remains forensic-only.
2201
2251
 
2202
- - §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with ```` ```READ (worker:///docs/) ````. A complete `[start-end]` segment in any numeric coordinate slot selects that inclusive decimal interval; brackets elsewhere retain ordinary path-glob meaning. Every rendered row appends one canonical model-facing leaf: the native operation name or invoked executor name, `/attempt` for a rejected emission. An executor leaf is derived from the durable submitted statement (its `runtime`), never an internal dispatch type or the current tool registry. Digits and punctuation in executor names remain part of the leaf. The leaf names identity rather than adding a resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive leaf is authoritative and a disagreement resolves 404. READ anchors use the canonical suffixed identity even when addressed by shorthand. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ`, `log:///**/python3`, and `log:///**/attempt` deliberately filter canonical leaves. An executor's output stream lives at that same item address under its runtime scheme — `sh:///1/2/3/sh#stdout` — so one `loop/turn/item/invocation` schema addresses log rows and streams. Error pointers, Problem instances, source attribution, and search use this same identity; client stream coordinates retain the numeric triple. Within a turn, sequence is arrival order, and the turn's prompt rows arrive first: the prompt publication row and any injected prompt rows are materialized before the program runs, so a turn that received a prompt holds it at `log:///L/T/1/prompt` (further prompts follow, oldest first) and the model's own operations come after — a contract, not an accident of dispatch order ({§packet-current-turn} names `L/T`).
2252
+ - §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with ```` ```READ (worker:///docs/) ````. A complete `[start-end]` segment in any numeric coordinate slot selects that inclusive decimal interval; brackets elsewhere retain ordinary path-glob meaning. Every rendered row appends one canonical model-facing leaf: the native operation name or invoked executor name, `/attempt` for a rejected emission. An executor leaf is derived from the durable submitted statement (its `runtime`), never an internal dispatch type or the current tool registry. Digits and punctuation in executor names remain part of the leaf. The leaf names identity rather than adding a resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive leaf is authoritative and a disagreement resolves 404. READ anchors use the canonical suffixed identity even when addressed by shorthand. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ`, `log:///**/python3`, and `log:///**/attempt` deliberately filter canonical leaves. Executor outputs instead use workspace-wide claims such as `sh:///ab3d5678#stdout` ({§execution-output-identity}); their source operation has log coordinates, but resource lifetime and identity are independent of that observation. Error pointers, Problem instances, source attribution, and search use this same identity; client stream coordinates retain the numeric triple. Within a turn, sequence is arrival order. Inbound SEND rows publish before the program runs ({§message-arrival}); a turn receiving messages holds the first at `log:///L/T/1/SEND`, followed by further arrivals oldest first, then the model's operations ({§packet-current-turn} names `L/T`).
2203
2253
  - §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — KILL takes a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}), like a folder-scoped FIND: ```` ```KILL (log:///1/2) <1,-1> ```` suppresses turn 1/2's bodies. A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. A targetless KILL is 400.
2204
2254
  - §log-curation-set-selection **Row selection and body scope are independent** — target/glob and an optional heading pattern (```` ```KILL (log:///**) [{"pattern": "~stale"}] ````, every dialect a FIND over rows accepts) compose by intersection into the affected row set. An optional `<L>` or `<SL,EL>` then intersects each selected canonical body; it never paginates or changes the selected set. Thus ```` ```KILL (log:///**/READ) <17,-1> ```` may change long READs and no-op on short ones while reporting every selected row in `matched`.
2205
2255
 
@@ -2207,7 +2257,8 @@ ordinary bounded bodies expose their displayed and complete chunk extents there.
2207
2257
 
2208
2258
  | KILL result | Packet receipt |
2209
2259
  |---|---|
2210
- | Successful log-item or line curation, including a 204 no-op | Not shown, including the first packet after the operation. |
2260
+ | Successful log-item or line curation (200) | Not shown, including the first packet after the operation: the rows that are gone are the receipt. |
2261
+ | A curation that matched nothing (204) | Shown once, in the packet of the very next turn, then retired like any other row. A success and a mismatch are not both silent: the model cannot otherwise tell that its earlier KILL is what emptied the selection (#779). |
2211
2262
  | Failed log curation | Visible with its ordinary Problem. |
2212
2263
  | Non-log target: file, worker, stream, or other resource | Ordinary scheme-owned receipt. |
2213
2264
 
@@ -2257,7 +2308,7 @@ flowchart LR
2257
2308
  body --> recall["READ log:///…<br/>selects untrimmed content"]
2258
2309
  ```
2259
2310
 
2260
- §edit-receipt-removed-text **A pure deletion's receipt quotes what it removed.** An applied effect that inserted nothing and removed at least one line carries `removedText` — the removed text, first 40 lines — projected on the wire as `removed`; an effect that inserted anything carries no such field, its resulting context shows the change.
2311
+ §edit-receipt-removed-text **A pure deletion's receipt quotes what it removed.** An applied effect that inserted nothing and removed at least one line carries `removedText` — the removed text, its first `PLURNK_SERVICE_EDIT_RECEIPT_REMOVED_LINES` lines — projected on the wire as `removed`; an effect that inserted anything carries no such field, its resulting context shows the change.
2261
2312
 
2262
2313
  §edit-receipt-anchored-context **An applied EDIT's resulting context carries anchors.** The bounded resulting context each effect renders (`PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` around and inside the landed region) is rendered exactly as a READ renders — `@xxxxx L:text`, hashed with the resource's READ identity ({§line-anchors}) — so a later operation can cite the landed lines by anchor without a READ. A scheme that supplies no identity keeps the line-numbered form.
2263
2314
 
@@ -2273,9 +2324,9 @@ per-operation projection on `rx`; the aggregate remains inside dispatch.
2273
2324
  | Full `revision` | not projected | SHA-256 identity of the complete landed channel body, retained for forensics. No operation takes a revision; it is neither a lookup nor a compare-and-swap token. |
2274
2325
  | `unit`, `before`, `after` | `extent` | Whole-line batches use line counts. A batch containing any exact four-coordinate edit uses Unicode code-point counts. |
2275
2326
  | `parseIssues.before`, `parseIssues.after` | `parseIssues` as `before→after` | Parser-recovery counts for complete source and landed revisions; omitted when both are clean or either is unavailable. |
2276
- | `effect.requested`, `source`, `result` | `range` | The admitted marker and its normalized mapping from the common source snapshot into the landed body. |
2327
+ | `effect.source`, `result` | `effect` as `<source> -> <result>` | Resolved scopes mapping the source snapshot into the landed body; the admitted marker stays in durable `requested` and `tx`. |
2277
2328
  | `effect.removed`, `inserted` | `change` | Removed and inserted counts in the receipt unit. |
2278
- | `effect.removedText` | `removed` | {§edit-receipt-removed-text}: a pure deletion's removed text, first 40 lines; absent when the edit inserted anything. |
2329
+ | `effect.removedText` | `removed` | {§edit-receipt-removed-text}: a pure deletion's removed text, its first `PLURNK_SERVICE_EDIT_RECEIPT_REMOVED_LINES` lines; absent when the edit inserted anything. |
2279
2330
  | `effect.context` | Canonical row body | Numbered physical lines at each landed boundary, bounded symmetrically by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
2280
2331
  | `disposition`, `requested` | `disposition`, `requested` | A reviewer-replaced batch preserves the authored marker while stating that its attributed effect was superseded. |
2281
2332
  | `replacement` | `replacement`, `change`, canonical proposal-owner body | The one whole-resource effect actually applied by the reviewer replacement; never duplicated across authored rows. |
@@ -2283,8 +2334,8 @@ per-operation projection on `rx`; the aggregate remains inside dispatch.
2283
2334
  §edit-result-receipt-truth **Receipts describe committed state.** Each EDIT
2284
2335
  carries its own landed revision, extent, and optional `parseIssues` transition
2285
2336
  for its complete source and landed revisions. When the proposal lands
2286
- unchanged, the row also carries its requested
2287
- marker, source/result mapping, counts, and context. For configured count `C`,
2337
+ unchanged, the row carries its source/result mapping, counts, and context;
2338
+ the authored marker remains in durable evidence. For configured count `C`,
2288
2339
  the context contains up to `C` surrounding lines and the first and last `C`
2289
2340
  landed lines at the result boundaries. Overlapping windows coalesce; coordinate
2290
2341
  jumps expose an omitted middle. A deletion instead shows up to `C` lines on
@@ -2469,7 +2520,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
2469
2520
  channel derivation under `{§scheme-catalog-parse-issues}`.
2470
2521
 
2471
2522
  §scheme-catalog-aside **Catalog aside.** `aside` is the exact channel
2472
- derivation's `{§mimetype-summary}`. Prose is clipped to at most 256 Unicode
2523
+ derivation's `{§mimetype-summary}`. Prose is clipped to at most `PLURNK_SERVICE_CATALOG_SUMMARY_CHARS` Unicode
2473
2524
  code points including a visible terminal ellipsis, so a row stays one line
2474
2525
  of orientation; an invocation-form witness — a summary that is one fenced
2475
2526
  operation, the shape every tool family's summary takes
@@ -2484,8 +2535,8 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
2484
2535
  that shape, while deeper first-segment directories collapse to the one-element
2485
2536
  group `[{ path: "dir/**", items, weight }]`, where the selector and both aggregates
2486
2537
  describe the exact recursive subtree. Scope summaries are navigation
2487
- metadata, not resources. Markerless FIND returns positions 1–16 in the
2488
- selected unit; `<N,M>` selects an inclusive page and `<1,-1>` explicitly
2538
+ metadata, not resources. Markerless FIND returns the first page
2539
+ ({§markerless-first-page}) of positions in the selected unit; `<N,M>` selects an inclusive page and `<1,-1>` explicitly
2489
2540
  selects all. `range` reports the unit, complete result total, normalized
2490
2541
  request, and returned positions ({§range-extent}). `itemsWeightTotal` weighs the complete matched set while
2491
2542
  `returnedItemsWeightTotal` weighs the returned resource page; in exact
@@ -2507,40 +2558,47 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
2507
2558
 
2508
2559
  SEND AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, metadata, lineMarker }`.
2509
2560
 
2510
- - **Message:** SEND addresses its recipient through {§send-dispatch}, or the user when targetless. It never controls the turn.
2511
- - **Disposition:** TASK declares the complete current inventory; {§task-inventory-intent} reduces its statuses, never its prose, to one workflow intent.
2561
+ - **Message:** SEND delivers to an actor, endpoint or exact message address. Targetless SEND answers observed Open Messages.
2562
+ - **Workflow:** WAIT yields; successful reply delivery and settled work permit completion at the end of the whole program. NOTE retains memory.
2512
2563
 
2513
- §wait-obligation-matrix **Runtime resolution.** Apply this table after earlier operations have executed. The durable TASK retains its authored inventory even when the actual outcome differs. A live obligation is a worker-owned unresolved child or non-detached stream, read as one row from the `worker_obligations` view ({§worker-obligations}). Unobserved results include this turn's retrievals, mutations and failures, and undelivered stream or child conclusions. Scope `<timeout[,poll]>` follows {§worker-wait-timing} only for a waiting intent.
2564
+ §worker-obligations A worker holds its unresolved children and open non-detached
2565
+ streams (`worker_obligations`); `loop_obligations` names them per loop. The
2566
+ packet's Delegation list, WAIT, completion and drain wake settlement use that
2567
+ same durable liveness.
2514
2568
 
2515
- §worker-obligations **What a worker holds is one durable row.** `worker_obligations(worker_id, streams, workers)` is a view: `streams` is an open subscription of the worker's with `detached = 0` (`subscriptions.detached` is written when a `<-1>` spawn opens its stream, so a detached spawn is nobody's obligation by the row, never by asking the exec scheme's memory), and `workers` is a child with an unresolved loop — the same liveness the Delegation section shows, so the 409 gate and the section the model reads cannot disagree ({§child-orientation}). The completion gate ({§send-premature-terminate}), the wait matrix, and the drain's wake settlement all read `worker_live_obligations`; nothing computes the union in the process.
2569
+ §wait-obligation-matrix **End-of-program resolution.** Execute all admitted operations and settle optimistic work before applying this table. WAIT is an optional yield, not an end-of-program delimiter.
2516
2570
 
2517
- | Inventory intent | Runtime condition | Outcome | Model-facing feedback |
2518
- |---|---|---|---|
2519
- | TASK omitted | At least one authored operation | 102; no synthetic TASK, warning, or strike | None |
2520
- | explicit empty inventory | Always | 409 receipt; continue, no strike (operator, 2026-09-12) | `No tasks were supplied. Submit a nonempty TASK inventory.` |
2521
- | continue | Always | 102; no implicit join or idle strike | None |
2522
- | todo | Always | 102; no strike | None |
2523
- | wait | Finite timeout, positive poll, or live obligation | 202; durable park and wake of the same loop | Wait timing metadata |
2524
- | wait | No wait obligation; results or curation await the next packet | 102 | Existing result evidence |
2525
- | wait | No wait obligation or unobserved result | 102; no strike | `Nothing is in flight and no timed or polled wait is set. Continuing.` |
2526
- | complete, fail | The loop holds prompt frames it has not yet published ({§completion-defers-to-prompts}) | 102; no strike; the next packet publishes them | `Completion deferred: 1 new prompt arrived during this turn. It is in this packet; a response and a TASK now complete.` |
2527
- | complete | Live work: an open stream or a live child worker ({§completion-joins-live-work}) | 202; durable park and wake of the same loop; no strike | Join detail naming the work, read when the wake lands |
2528
- | complete, fail | Same-turn failures, or settled results the next packet carries — this turn's receipts, a concluded stream, a terminated child ({§completion-defers-to-results}) | 102; no strike; the next packet carries them | Read-time deferral detail naming them |
2529
- | complete | No blocking obligation, or administrative producer | 200 | None |
2530
- | fail | Otherwise; live work is cancelled, never waited for | 499; cancel unresolved descendant scope | `All tasks in the final inventory failed.` |
2531
-
2532
- A timing scope on a non-waiting inventory is ignored with `Wait timing was not applied because no waiting intent was selected.` It does not override the inventory. Every continuation retains the same loop's budgets and strike rail. No-op waiting never invents success.
2533
-
2534
- §loop-response-messages **The response is the last message.** The loop's response is the complete authored body of its last successful targetless SEND, or SEND to one of this loop's own prompts ({§send-prompt-acceptance}), in turn and operation order. Earlier messages reach the client as they are delivered and stay log rows; they are not part of the response, so a corrected answer or a repeated one after a refused completion delivers once. Other directed SEND, TASK, asides, interstitial text, inherited rows and ambient observations never count. The projection reads immutable executed operation evidence, not the curated log projection: KILL cannot retract a delivered message, and a later failure, cancellation or refused completion keeps the last message. A task inventory never becomes a synthetic answer. Terminal status and Problem Details remain independent of this response content. A parent receives its child's response as the child's conclusion (operator, 2026-09-11).
2571
+ | Condition, in evaluation order | Outcome |
2572
+ |---|---|
2573
+ | Worker or loop already cancelled/terminal | Preserve that result. |
2574
+ | Administrative program | Finish its transaction without adjudicating another model loop's work. |
2575
+ | New unpublished message | Continue; publish it in the next packet. |
2576
+ | Live work and either WAIT or no unanswered messages | Park the same loop; message arrival, child or stream settlement, or stream cadence wakes it. |
2577
+ | WAIT without live work | Continue; never invent a future wake. |
2578
+ | Unanswered messages | Continue. |
2579
+ | Unobserved operation results, failures, child results or stream conclusions | Continue; the next packet presents them. |
2580
+ | No outstanding messages, live work or unobserved results | Conclude successfully, without a synthetic operation. |
2581
+
2582
+ An empty emission is handled by {§empty-turn}, not this completion rule. Ordinary strikes,
2583
+ cycles and execution limits remain independent. NOTE and successful KILL do not themselves
2584
+ require another observation turn. Failed KILL and every other operational result do.
2585
+
2586
+ §loop-response-messages **A response is a recorded delivery.** A successful SEND reply records
2587
+ the exact message addresses it answers. All replies remain independently recoverable in
2588
+ message history, in execution order, regardless of producer. An actor-addressed SEND that
2589
+ does not answer a message, WAIT, NOTE, asides, inherited rows and ambient observations are
2590
+ not replies. Curation cannot retract delivery; cancellation or later failure retains it.
2591
+ Attachment-only replies retain their attachments without replacing earlier text. A child
2592
+ conclusion carries its execution outcome under {§send-undelivered-child-term}, not a second delivery.
2535
2593
 
2536
2594
  §loop-terminal-authorship **Terminal authorship is explicit when external.**
2537
2595
 
2538
2596
  | `terminated_by` | Meaning | Presentation |
2539
2597
  |---|---|---|
2540
2598
  | `NULL` | The model's own terminal or an engine verdict whose exact result already carries the story. | No authorship marker. |
2541
- | `cancel` | An external client cancelled the structured scope ({§methods-loop-cancel}). | COLLECT and the termination delta prepend a cancellation marker to the exact Problem's presentation, so cancellation cannot masquerade as a deliverable. The model's prior log rows remain untouched. |
2599
+ | `cancel` | The structured scope was explicitly cancelled, through the client or worker KILL ({§methods-loop-cancel}). | COLLECT and the termination delta prepend a cancellation marker to the exact Problem's presentation, so cancellation cannot masquerade as a deliverable. The model's prior log rows remain untouched. |
2542
2600
 
2543
- The engine's failure terminals — **500** (strike threshold) and **508** (cycle), {§engine-rails} — are never the model's to pick; they are the engine ruling the loop failed. The surface is small on purpose: the model says done, waiting, or giving up, and is never asked to hold a correct opinion about *how* it failed or *whether* it can be woken — the engine decides those from state.
2601
+ The engine's failure terminals — **500** (strike threshold) and **508** (cycle), {§engine-rails} — are never the model's to pick; they are the engine ruling the loop failed. The model answers, waits or cancels its scope; the engine derives the lifecycle outcome from that state.
2544
2602
 
2545
2603
  Disposition outcomes follow {§wait-obligation-matrix},
2546
2604
  {§completion-joins-live-work}, and {§completion-defers-to-results}. Strike
@@ -2549,29 +2607,44 @@ accounting and model-visible failure evidence remain separately owned by
2549
2607
 
2550
2608
  - §send-target-recipient **A SEND target is a recipient.** A model's directed SEND
2551
2609
  addresses a worker (```` ```SEND (worker://<name>) ````), an outbound agent (`a2a://`),
2552
- or a scheme that implements SEND (an `https://` POST). A SEND to a scheme the model may not write (the prompt, the
2610
+ or a scheme that implements SEND (an `https://` POST). A SEND to a scheme the model may not write (the
2553
2611
  log) is refused 400 `send-target-not-a-recipient`, never the unrelated writer
2554
2612
  rule. The detail states only that the addressed scheme is not a recipient;
2555
2613
  neutral recovery distinguishes targetless replies from directed SEND without
2556
2614
  guessing which one was intended. A scheme that does not implement SEND
2557
2615
  answers its ordinary factual 501 without grafting a guessed recovery onto it.
2558
- - §send-prompt-acceptance **One tolerated exception: this loop's own prompt.** The packet
2559
- lists `prompt://<worker>/<loop>/<id>` addresses under Active Prompts, and a model that
2560
- addresses one of them means what an untargeted SEND means. The engine accepts a model
2561
- SEND to a prompt of the current worker and loop as exactly that response: it dispatches
2562
- as the untargeted case, the row keeps the address the model wrote, and the body counts as
2563
- the loop's response under {§loop-response-messages}. Nothing is taught about the form and it
2564
- creates no per-prompt result structure; a prompt of another loop or another worker stays
2565
- `400 send-target-not-a-recipient`. An undocumented acceptance in the same spirit as KILL
2566
- in the completion turn, not a recipient.
2567
- - §send-response-receipt **A reply's receipt names its recipients.** A delivered untargeted
2568
- SEND (and a SEND accepted under {§send-prompt-acceptance}) carries `recipients`: the loop's
2569
- Active Prompts, oldest first, exactly as the packet lists them. The row shows where the text
2570
- went, so a model that meant a worker, a stream, or an operation sees the user received it.
2571
- - §empty-turn **A response with no operation is a turn, not a retry.** When the parser finds
2572
- no operation and no other hard error (prose, bare headings outside fences, an empty
2573
- response), the emission is admitted as an empty turn (operator, 2026-09-12): its text and
2574
- reasoning are stored like any turn's (`ops:///`, `reasoning:///`), the model's own message
2616
+ - §send-response-receipt **A reply records exactly which messages it answers.** A successful
2617
+ reply carries `answers`, the immutable message addresses it answered, not recipient actors. Targetless SEND
2618
+ answers this loop's published, unanswered messages, oldest first. SEND to an exact message
2619
+ address answers only that message; SEND to an actor endpoint remains ordinary communication
2620
+ and answers no assignment implicitly. An unpublished arrival cannot be answered by the
2621
+ targetless shorthand. Failed delivery answers nothing. Reply accounting reads executed
2622
+ delivery evidence, never log visibility or the mere existence of a later SEND.
2623
+ - §prose-conclusion **Prose is the answer.** An admitted response whose content has no
2624
+ operation, attempts none ({§operation-attempt}), was not cut at the output
2625
+ allowance, is not empty, says something outside its quotations ({§quotation}: a reply that is
2626
+ nothing but quoted material is a misfenced program) and holds no misplaced operation fence
2627
+ (`must start its line to run`) is the model's answer (operator, 2026-09-18, #761): the engine
2628
+ admits it as a targetless SEND whose body is the trimmed content, positioned on line 1. It
2629
+ answers the open messages, reaches clients and a parent exactly as a SEND does, and meets the
2630
+ completion barrier as a SEND does ({§completion-joins-live-work},
2631
+ {§completion-defers-to-results}). Reasoning NOTEs ride with it. The model is taught
2632
+ "respond without performing any OPs" and is never taught the SEND. A reply wrapped whole in one
2633
+ `markdown` or `md` fence is delivered as that fence's content ({§quotation}). Its row is stored as the
2634
+ SEND that delivers it (reply accounting, delivery and clients read SEND rows) but carries
2635
+ `attrs.answer = "prose"` and `resource: ops://<worker>/<loop>`, and is addressed and rendered
2636
+ under the leaf `answer` (`log:///1/2/2/answer`), never as a SEND the model did not write.
2637
+ - §loop-answer **A loop's address is what it said.** READ `ops://<worker>/<loop>` resolves to
2638
+ the latest reply the loop gave to the message that started it: a prose conclusion's text or
2639
+ the body of a SEND that targeted that message. A running loop without one is 425; a loop that
2640
+ ended without one is its terminal problem (404 when it ended 2xx). `ops://<worker>/<loop>/<turn>`
2641
+ remains that turn's emission. A concluded child's `loop_termination` row to its parent carries
2642
+ `answer: ops://<child>/<loop>` beside its status. Witness: `test/intg/loop-answer.test.ts`.
2643
+ - §empty-turn **A response with no operation that is not an answer is a turn, not a retry.**
2644
+ When the parser finds no operation and no other hard error, and the response is not an
2645
+ answer under {§prose-conclusion} — an operation attempt, prose cut at the output allowance,
2646
+ or an empty response — it is admitted as an empty turn (operator, 2026-09-12): its text and
2647
+ reasoning are stored like any turn's (`ops://<worker>/`, `reasoning://<worker>/`), the model's own message
2575
2648
  stays in the next packet's history, that packet carries one `turn_no_operations` notice and
2576
2649
  any {§bare-heading-advisory} notices, the turn continues at 102, and the strike rail counts
2577
2650
  one progress-contract strike, so a model that only talks strikes out at the ordinary
@@ -2581,8 +2654,9 @@ accounting and model-visible failure evidence remain separately owned by
2581
2654
  EDIT or KILL carrying `[metadata]` for a scheme whose manifest takes none runs without it,
2582
2655
  and the packet carries one `metadata_ignored` notice naming the scheme (operator,
2583
2656
  2026-09-12: a gentle warning, never a refusal). The `pattern` option never reaches this
2584
- path; it is lifted into the matcher at parse time ({§matcher-option}). Executions, WORK and FORK
2585
- own their slot and receive it whole ({§env-option}); a key they do not take is their own 400.
2657
+ path; it is lifted into the matcher at parse time ({§matcher-option}). SEND recipients,
2658
+ executions, WORK and FORK own their input and receive it whole ({§send-resource-attachments},
2659
+ {§env-option}); a key they do not take is their own 400.
2586
2660
  - §send-looks-like-operation **A reply never begins with an operation heading.** When a model's
2587
2661
  untargeted SEND has, as its first non-blank line, a line that parses alone as one clean
2588
2662
  heading naming an operation this worker could perform — a Plurnk operation, or a registered
@@ -2600,75 +2674,29 @@ accounting and model-visible failure evidence remain separately owned by
2600
2674
  as a literal — on a reply's first line that is prose. Origin: the 2026-09-11 dogfood,
2601
2675
  where four operations on the line after their fences were delivered as four 200 replies and the
2602
2676
  loop then parked fifteen minutes on receipts that could never arrive.
2603
- - §send-idle-turn **Inventory-only continuation is valid.** An `in_progress` inventory continues whether or not another operation ran, including while children or streams are live. TASK is operational state; neither absence of other operations nor a not-ready READ may replace its intent with an implicit park. Exact repeating activity remains subject to {§engine-cycle-evidence}.
2604
- - §send-premature-terminate **Premature terminate — the pending set.**
2605
- A model's completion turn permits SEND, TASK, and KILL. Every other
2606
- fired operation requires another packet, regardless of success, stream
2607
- timing, or empty results. KILL does not erase other observation requirements
2608
- or failed results. Execution is judged from durable
2609
- operation records, never the curated log projection. Pending work has two states:
2610
- **live obligations** (open
2611
- streams/spawns and live child workers) and **completed-but-unobserved
2612
- results** (every same-turn non-SEND/TASK/KILL operation, terminal stream output
2613
- without a terminal foisted READ, and child results queued for the next packet).
2614
- The set is judged at the disposition's own dispatch, after
2615
- earlier operations in the emission. `[200]` over a **live** member joins it
2616
- ({§completion-joins-live-work}); a claim over only completed-but-unobserved
2617
- members is a deferral ({§completion-defers-to-results}). Neither is a refusal
2618
- and neither strikes. The pending kinds are `streams`, `workers`, `receipts`,
2619
- `failed-stream-results`, and `worker-results`; a receipt names them and never
2620
- embeds commands, stream handles, result bodies, or a presumed recovery. A
2621
- nonempty all-`failed` inventory crosses the same deferral and then abandons
2622
- regardless of live work, which it cancels rather than waits for.
2623
- - §completion-joins-live-work **A completion over live work is a join.** A scope
2624
- that says done while its own work runs — an open stream, a live child worker —
2625
- is asking to leave with that work unfinished, and the two exits structured
2626
- concurrency allows are join and cancel. The `completed` inventory takes the
2627
- join: the TASK answers 202, the loop parks untimed on the live obligation
2628
- exactly as a `waiting` inventory would, and the settle edge wakes it with what
2629
- concluded in the packet; the model's next TASK decides with that result in
2630
- front of it, so nothing completes on an answer written before the work
2631
- finished. The `failed` inventory takes the cancel. The join's `detail` is read
2632
- when the wake lands and speaks from that moment; its `attrs` carry `waiting`
2633
- and the pending kinds. It is never a strike: the review contract has no
2634
- violation left, and the rail's remaining sources are hard results, cycles and
2635
- empty turns ({§engine-rails}). A stream the model meant to leave running parks
2636
- the loop until it ends, as a model-written `waiting` would; KILL before the
2637
- claim is the way to leave it running (operator, 2026-09-14: "politely
2638
- converting completed into waiting when there are streams or workers in-flight").
2639
- - §completion-defers-to-results **Settled results defer a terminal; they never strike.**
2640
- A completion or abandonment claimed over results the model could not yet have
2641
- seen — this turn's failed operations, this turn's receipts (successful execution
2642
- results included, not only READ/FIND), a concluded stream's result, a terminated
2643
- child's result — is deferred: the TASK answers 102 with no Problem and no strike,
2644
- the loop continues, and the next packet carries what deferred it. The engine
2645
- owns every observe edge, so such a claim is early in the observation order, not
2646
- false about the world. After observing the results, the model can continue work,
2647
- revise its response, or conclude with TASK alone while retaining its last SEND
2648
- ({§loop-response-messages}, {§send-undelivered-child-term}).
2649
- The deferral's `detail` is read one packet later, beside the results it names,
2650
- and speaks from that moment: a receipts-only deferral names the distinct
2651
- blocking operations in execution order using their model-facing log names
2652
- ({§log-coordinate-hierarchy}), plus `stream completion` for undelivered terminal
2653
- stream results; a results deferral names the landed kinds; a failure deferral
2654
- counts the failures. These deferrals and the live-work join receipt share the
2655
- conditional guidance: `If your final response has already been sent and these
2656
- results require no further work or response revision, submit only TASK.` This
2657
- avoids repeating a delivered response, not delivering one; newly arrived prompts
2658
- retain their distinct feedback under {§completion-defers-to-prompts}. Their
2659
- `attrs` carry the pending kinds or the failure count. The rail's streak never
2660
- enters the decision: a deferral is admissible at any streak, and a loop that
2661
- keeps issuing operations before each claim pays one packet per claim, never a
2662
- strike, until the cycle detector rules its repetition ({§engine-cycle-evidence}).
2663
- Operator, 2026-09-14: the barrier is safety and the rail is liveness; fail is
2664
- completed with a frowny face and crosses the same barrier.
2665
- - §send-administrative-terminal **An administrative terminal closes its own
2666
- transaction.** A client, plugin, or `_plurnk` operation program runs in its
2667
- own administrative loop. Its all-`completed` TASK concludes exactly that loop;
2668
- it neither claims nor consumes the Worker's model-visible pending set. Model
2669
- completion rails therefore apply only to a model-authored disposition.
2677
+ - §send-idle-turn **NOTE is memory, not a yield.** NOTE does not imply parking.
2678
+ With unanswered messages it continues; after replies and observation it may be the only
2679
+ operation in the program that concludes. Repetition remains subject to {§engine-cycle-evidence}.
2680
+ - §send-premature-terminate **Completion follows observation.** Every fired operation except
2681
+ SEND, NOTE, WAIT and successful KILL requires a subsequent packet. This barrier uses durable
2682
+ executed evidence, not curated rows. Fast completion, an empty result or curation cannot
2683
+ erase it. New arrivals are protected by {§completion-defers-to-messages}; no terminal verb
2684
+ or prose overrides this rule.
2685
+ - §completion-joins-live-work **Answered work still joins its live obligations.** Once all
2686
+ observed messages are answered, live children, non-detached streams park the same loop
2687
+ as WAIT does. Each ordinary wake presents the newly settled state; completion is evaluated
2688
+ again after the next program. KILL owns cancellation; a reply never cancels work implicitly.
2689
+ - §completion-defers-to-results **Results keep the loop running until observed.** Same-turn
2690
+ operations and failures, plus undelivered child or stream conclusions, require the next
2691
+ packet. This is ordinary continuation, not a strike or a synthetic refusal receipt.
2692
+ The already-delivered answer remains delivered. If observation warrants no further work
2693
+ or revision, a NOTE or curation-only program can conclude without repeating the answer.
2694
+ - §send-administrative-terminal **Administrative programs close their own transaction.**
2695
+ Their caller closes the administrative loop after execution; no terminal operation is
2696
+ manufactured. Initialization runs in the model loop without concluding it.
2697
+
2670
2698
  - §send-undelivered-child-term **Completion is not delivery.** A result becomes
2671
- observed only after crossing a packet boundary. An untimed waiting TASK parks only on
2699
+ observed only after crossing a packet boundary. WAIT parks only on
2672
2700
  live obligations. If work has completed but is unobserved, it continues
2673
2701
  directly to the next packet because the wake edge has already fired. A genuinely
2674
2702
  empty wait also continues under {§wait-obligation-matrix}, never concluding implicitly.
@@ -2725,6 +2753,15 @@ batch of 2026-08-29 showed the absolute `cwd` copied back into the target slot a
2725
2753
  family — and neither a command nor a working directory is ever a target. The default
2726
2754
  shell is written as its own fence, ```` ```sh ````; no runtime-less form exists.
2727
2755
 
2756
+ §exec-target-near-miss Two target near-misses have one reading each and are read
2757
+ without a diagnostic (#758). A directory target is never a program: with a body
2758
+ and no explicit `cwd`, the body runs with that directory as its working
2759
+ directory; without a body it is still `target-not-a-program`. A target in the
2760
+ executor's own scheme whose path can never be a stream (`sh:///daemon-env`;
2761
+ streams are eight hex digits) is the writer's name for the run: with a body, the
2762
+ body runs as if targetless; without one, the source read refuses as before. A
2763
+ real stream id is always the program source.
2764
+
2728
2765
  §exec-tool-fall-through **A tool run as a shell command is named at the failure
2729
2766
  site.** A bare shell command whose program is the name of a tool published by
2730
2767
  another enabled runtime (`brave_web_search {…}` under the default shell) exits
@@ -2820,45 +2857,30 @@ Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor
2820
2857
  **Timeout and poll — `<T,P>` on the `<L>` slot (grammar 0.74.20).** An execution
2821
2858
  repurposes the line-marker slot as `<timeout, poll>` in **minutes** — agentic
2822
2859
  latencies make a sub-minute horizon a trap — converted at the parse boundary to the
2823
- catalog's internal `stream.seconds`. The TASK `<T>` wait horizon is minutes too.
2824
-
2825
- §exec-timeout `T` (`mark[0]`) caps the spawn's lifetime. At `T>0` the service
2826
- aborts it — a bounded reap, polite signal then SIGKILL after
2827
- `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and stamps the stream **504**, distinct
2828
- from a deliberate kill (499) or a clean exit (200). Absent is unbounded but
2829
- loop-life bounded — reaped on every loop terminal except 202 — the
2830
- background-stream behavior. **`-1` is unbounded and detached**: the spawn
2831
- outlives its loop's terminal, 200 included. It never binds to the loop's
2832
- teardown and is nobody's obligation — completion is not gated by it, a waiting TASK does
2833
- not park on it, optimistic settlement looks past it — and it ends only by KILL,
2834
- the worker's total reap, or daemon shutdown; its late conclusion surfaces
2835
- without opening a loop. **`0` is turn-scoped**:
2836
- the stream is reaped at the worker's next pre-turn via the registry abort,
2837
- before the turn's own spawns, so it never survives into the subsequent turn;
2838
- its terminal output surfaces born visible like any close ({§exec-stream}).
2839
-
2840
- §exec-poll `P` (`mark[1]`) is the **poll cadence**, stored on the subscription.
2841
- While the loop is parked waiting for that stream, the daemon persists
2842
- the tightest open poll cadence on that exact wait and resumes the blocked
2843
- loop every P minutes, floored by `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS` so it cannot tick
2844
- faster than the optimistic settlement scale, to inspect progress. It does **nothing while the
2845
- loop is active** because ambient stream deltas already surface progress. An
2846
- open stream without `P` uses exponential backoff
2847
- (`PLURNK_SERVICE_EXEC_POLL_SEC` and `PLURNK_SERVICE_EXEC_POLL_TURNS`); explicit
2848
- `<,P>` wins and `<,0>` disables polling for that stream. Open subscriptions
2849
- aggregate into each wait's inherited observation policy as follows; an explicit
2850
- TASK poll interval overrides this aggregation ({§worker-wait-timing}):
2851
-
2852
- | Open-stream policies | Worker timer |
2853
- | --------------------------------------------- | ----------------------------- |
2854
- | Any positive `P` | The smallest positive cadence |
2855
- | No positive `P`, at least one omitted `P` | Exponential backoff |
2856
- | Every `P` is explicit zero | Disabled |
2857
-
2858
- Child-only joins never use this timer: child settlement is their durable wake
2859
- edge. Stream closure remains a wake edge under every poll policy.
2860
-
2861
- §exec-host-proposes **Effect-gating.** Each executor declares an `effect` (`pure` | `read` | `host`); the service maps it to policy (`EffectPolicy`). A `host` runtime (subprocess; file-backed sqlite) proposes under {§proposal}. Once accepted, it spawns and writes channels at its workspace execution address ({§execution-output-identity}), returning `102 Processing`. Channel state transitions (`active` → `closed`/`errored`) drive subsequent observations ({§channel-state}).
2860
+ catalog's internal `stream.seconds`. WAIT takes no timing; future wakes belong to the schedule family.
2861
+
2862
+ §exec-lifetime **How long a spawn may live is the fence's metadata, one field.**
2863
+ `[{"lifetime": …}]` takes a duration (`30s`, `30m`, `2h`), or one of three words;
2864
+ absent is `loop`. An execution takes no scope: a numeric coordinate on an
2865
+ executor target is refused `scope-unsupported` (400), naming the field.
2866
+
2867
+ | `lifetime` | The spawn |
2868
+ | ------------ | --------- |
2869
+ | a duration | Aborted at the deadline — a bounded reap, polite signal then SIGKILL after `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and the stream is stamped **504**, distinct from a deliberate kill (499) or a clean exit (200). |
2870
+ | `loop` (absent) | Loop-life bounded: reaped on every loop terminal except 202, the background-stream behavior. |
2871
+ | `turn` | Reaped at the worker's next pre-turn via the registry abort, before the turn's own spawns, so it never survives into the subsequent turn; its terminal output surfaces born visible like any close ({§exec-stream}). |
2872
+ | `detached` | Outlives its loop's terminal, 200 included. It never binds to the loop's teardown and is nobody's obligation — completion is not gated by it, WAIT does not park on it, optimistic settlement looks past it — and it ends only by KILL, the worker's total reap, or daemon shutdown; its late conclusion surfaces without opening a loop. |
2873
+
2874
+ **Cadence is the daemon's, never the model's.** While a loop is parked on an open
2875
+ stream the daemon wakes it on the worker's exponential backoff
2876
+ (`PLURNK_SERVICE_EXEC_POLL_SEC`, `PLURNK_SERVICE_EXEC_POLL_TURNS`, floored by
2877
+ `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`) to inspect progress; it does nothing while
2878
+ the loop is active, because ambient stream deltas already surface progress.
2879
+ Closure is a wake edge regardless. Child-only joins never use this timer: child
2880
+ settlement is their durable wake edge. A recurring check on the calendar is a
2881
+ schedule targeting yourself ({§schedule-delivery}), not a loop that polls.
2882
+
2883
+ §exec-host-proposes **Effect-gating.** Each executor — and each scheme operation that mutates something outside this process — declares an `effect` (`pure` | `read` | `host`); the service maps it to policy (`EffectPolicy`). The declarer states the FACT, the panel decides the POLICY, and one rule covers every operation: nothing that changes the world runs on nobody's authority. A `host` runtime (subprocess; file-backed sqlite) proposes under {§proposal}, and so does an outbound request that mutates a remote resource ({§http-outbound-proposes}). Once accepted, it spawns and writes channels at its workspace execution address ({§execution-output-identity}), returning `102 Processing`. Channel state transitions (`active` → `closed`/`errored`) drive subsequent observations ({§channel-state}).
2862
2884
 
2863
2885
  §entry-owner **Every entry belongs directly to one workspace.** Its immutable identity is `(workspace_id, scheme, authority, pathname)`. The workspace foreign key supplies lifetime; URI authority supplies the literal resource namespace. There is no entry-owner Worker, synthetic commons actor, caller-relative alias, or per-Worker access grant. Core binds one canonical coordinate through {§entry-address-resolution} for every operation and consumer. Producer and subscriber Worker ids describe causal activity, not ownership.
2864
2886
 
@@ -2908,15 +2930,14 @@ inventory; allocation never rewrites the submitted operation's target.
2908
2930
 
2909
2931
  §exec-readpure-ungated A `read` runtime (observes external state, e.g. search) or `pure` runtime (no observable effect, e.g. `:memory:` sqlite) is side-effect-free → **auto-run**: no proposal, no human gate, no notification. Core persists the prepared operation before applying it; that write-ahead staging has no resolution waiter and therefore cannot enter proposal discovery ({§proposal-list}). It skips the gate a host command faces, but it does NOT resolve in-band — like every exec it backgrounds and streams, its output reaching the model through the environment-observation injector (a foisted READ of newly publishable stream content each turn, {§exec-stream}), never a same-turn receipt.
2910
2932
 
2911
- §effect-policy-tunable **Effect admission is deployment-tunable.** The default
2912
- map (`host` proposes; `read`/`pure` auto-run) is the contract; the operator may
2913
- override it deployment-wide with `PLURNK_SERVICE_EFFECT_POLICY`, a
2914
- comma-separated `<effect>:<policy>` list (e.g. `read:propose` proposes even
2915
- read effects). Unlisted effects keep the default. An invalid entry — unknown
2916
- effect, unknown policy, or a non-`<effect>:<policy>` shape — fails daemon boot
2917
- loudly rather than degrading admission.
2933
+ §effect-policy-tunable **Effect admission is one knob per effect.**
2934
+ `PLURNK_SERVICE_EFFECT_HOST`, `PLURNK_SERVICE_EFFECT_READ` and
2935
+ `PLURNK_SERVICE_EFFECT_PURE` each say `propose` or `auto`, and together they are
2936
+ the whole map: no effect's admission is held in code, so a deployment that
2937
+ proposes even reads says so in one place an operator can read. An invalid value
2938
+ fails daemon boot by the knob's name rather than degrading admission.
2918
2939
 
2919
- After all non-SEND operations dispatch, the initiating turn applies {§worker-optimistic-settlement} to only the execution streams it started, then dispatches its turn disposition against the refreshed lifecycle state. An older stream receives no renewed opportunity merely because another turn began. This is a settlement barrier before disposition, not sibling-operation serialization: dependent EXECs remain separate observed turns.
2940
+ After all non-WAIT operations dispatch, the initiating turn applies {§worker-optimistic-settlement} to only the execution streams it started, then resolves the whole program against the refreshed lifecycle state. An older stream receives no renewed opportunity merely because another turn began. This is a settlement barrier before completion, not sibling-operation serialization: dependent executions remain separate observed turns.
2920
2941
 
2921
2942
  §exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*, in
2922
2943
  two states and no others:
@@ -2924,7 +2945,16 @@ two states and no others:
2924
2945
  | state | what the model receives |
2925
2946
  |---|---|
2926
2947
  | active | nothing in the Log. The `## Delegation` stream pointer names the stream with each channel's size and its growth since the last packet ({§child-orientation}); the model READs any range it wants, and every READ of a stream channel carries `terminal: false` while it runs and `terminal: true` once it has concluded, so an empty page is never mistaken for a finished command that printed nothing (operator, 2026-09-13). |
2927
- | terminal | ONE `origin=_plurnk` READ at the execution's channel address, born visible, that is exactly a markerless READ of the channel — its bounded first page ({§read-selection-projection}, the whole channel when it fits, the channel's own mimetype), the `range` or `region`, terminal status and Problem, `terminal: true`, any producer-supplied integer `exitCode`, and `source: log:///<coord>/<runtime>` linking the causal invocation. The packet renders that address under `stream`, exactly as the invocation row links its output, never under `target`: a stream is observed, not a slot to author. |
2948
+ | terminal | ONE `origin=_plurnk` READ at the execution's channel address, born visible, that is exactly a markerless READ of the channel — its bounded first page ({§read-selection-projection}, the whole channel when it fits, the channel's own mimetype), the `range` or `region`, terminal status and Problem, `terminal: true`, and any producer-supplied integer `exitCode`. The packet identifies the read resource with `path`, exactly as an explicit READ does ({§log-address-metadata}). |
2949
+
2950
+ §stream-observation-result **One liveness fact.** The durable READ result owns
2951
+ `terminal`, derived from its selected channel's state, for explicit and automatic
2952
+ observations alike, independently of mimetype: `active` gives false, `closed` or
2953
+ `errored` gives true, and `static` has no streaming liveness field. Packet
2954
+ projection preserves that Boolean and any included
2955
+ integer `exitCode`, even for an empty body. An automatic observation's atomic
2956
+ publication transition consumes the same result flag; private log attributes
2957
+ retain only the publication offset, not a second liveness value.
2928
2958
 
2929
2959
  §exec-concurrency **Bounded admission per workspace (#389).** At most
2930
2960
  `PLURNK_SERVICE_EXEC_CONCURRENCY` executions run at once in one workspace (shipped `12`;
@@ -2974,19 +3004,40 @@ remains pending until every selected channel's terminal READ crosses the next
2974
3004
  packet boundary. The execution row separately records the authored invocation.
2975
3005
 
2976
3006
  ```` ```KILL (<runtime>:///<eight-hex-id>) ```` cancels an active subprocess via
2977
- the subscription registry's stored controller. A terminal stream is immutable:
2978
- 499 returns 410 (already killed), every other terminal status returns an RFC
2979
- 9457 409 Problem carrying `terminalStatus`, and an unknown address returns 404.
3007
+ the subscription registry's stored controller. A terminal stream is immutable,
3008
+ and KILL of one is satisfied rather than refused: it returns 200 carrying the
3009
+ recorded `terminalStatus` (499 when it was already killed); an unknown address
3010
+ returns 404 (#757).
2980
3011
  The runtime scheme participates in the durable lookup; a completed `sh:///`
2981
3012
  stream cannot fall through an internal `exec`-only query. {§stream-control}
2982
3013
 
3014
+ §workspace-env **Workspace environment.** The `env` family has workspace defaults and
3015
+ worker overrides. Its six verbs accept `scope: "workspace" | "worker"`; model calls
3016
+ default to `worker`. Client actions bind the scope in `workspace.env.*` or
3017
+ `worker.env.*`. An explicit scope must agree with that action's context.
3018
+
3019
+ | Consumer | Composition, later layers win |
3020
+ |---|---|
3021
+ | Worker command | Admitted ambient environment → workspace entries → worker entries → invocation `env` |
3022
+ | Shared capability process | Admitted ambient environment → workspace entries → explicit capability launch options |
3023
+
3024
+ Each layer uses the same value and masking rules. A worker's list includes workspace
3025
+ defaults by reference with `origin: "workspace"`; worker overrides and masks remain
3026
+ worker-owned. Enabling an inherited entry clears this layer's mask, not a mask in a
3027
+ lower layer; an explicit local value can override that lower layer. A mask follows
3028
+ the name even when its lower-layer origin changes. Removing an override reveals the lower entry disabled, as for a service
3029
+ baseline. Forking copies only worker state, not the workspace defaults. Workspace edits
3030
+ affect subsequent launches, not existing processes or other workspaces. A shared
3031
+ capability never acquires an invoking worker's overrides or ownership.
3032
+
2983
3033
  §exec-env-scoped **Scoped environment.** An execution subprocess receives a composed
2984
3034
  environment, never the host's. Two mechanisms apply in order, and they are different kinds
2985
3035
  of thing. First the **ambient policy**, a ceiling: `PLURNK_SERVICE_EXEC_ENV_INHERIT` names
2986
3036
  what the host's environment may contribute at all and `_EXCLUDE` narrows that, both taking
2987
3037
  exact names or one trailing-`*` prefix glob, both ordinary operator knobs under
2988
3038
  {§operator-config-env-defaults}. A worker document or a heading modifier narrows the ceiling
2989
- further; nothing downstream widens it. The worker document is the Worker's `env` state
3039
+ further; nothing downstream widens ambient admission. Explicit entries may supply their
3040
+ own non-reserved values. Workspace defaults precede the Worker's `env` state
2990
3041
  ({§env-functionality}), read at the spawn: an enabled worker entry sets its own value, a disabled
2991
3042
  entry of either origin withholds the name, and what `list` projects is what the command
2992
3043
  receives. Then the **invariant**, which is not a knob:
@@ -3006,14 +3057,16 @@ nothing ambient — the allowlist is declared in `.env.defaults`, so an empty on
3006
3057
  policy rather than an unconfigured install.
3007
3058
 
3008
3059
  The full composition for one spawn, nearest setter winning for defaults and ceilings immune,
3009
- is package floors → operator cascade → ambient policy → worker document → the op's modifier →
3060
+ is package floors → operator cascade → ambient policy → workspace entries → worker entries → the op's modifier →
3010
3061
  body prefixes.
3011
3062
 
3012
3063
  - §env-option **The op's environment.** `env` is the service's key in the heading's `[metadata]`
3013
3064
  ({§scheme-metadata-modifier}): `[{"env": {"NAME": "value"}}]`, an object of string values.
3014
3065
  On an executor fence it is that process's environment over the Worker's own
3015
3066
  ({§env-functionality}) — the layer nearest the spawn, never entering the registry; a runtime
3016
- that runs in-process ignores the environment it is handed, so there it changes nothing. On
3067
+ that runs in-process has no process environment to change. A capability manager may
3068
+ retain explicit launch overrides when adding a process-backed definition; it never
3069
+ persists the composed ambient environment. On
3017
3070
  WORK and FORK it is the child's starting environment: after the copy the child inherits
3018
3071
  ({§functionality-scope}), each name lands as the child's own entry through the family's `add`,
3019
3072
  so a parent hands down its registry and overrides specific names for one child in one heading.
@@ -3022,7 +3075,7 @@ body prefixes.
3022
3075
  key WORK or FORK does not take is refused the same way. The durable row redacts the block
3023
3076
  wholesale ({§log-sensitive-request-evidence}); the spawn's record names each such value's
3024
3077
  provenance as the modifier's.
3025
- - §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits an executor fence followed by TASK; the wake-shaped world simply arrives one packet sooner. It extends selected runtimes beyond the ordinary {§worker-optimistic-settlement} cap before the next packet assembles. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
3078
+ - §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits an executor fence, optionally followed by WAIT; the wake-shaped world simply arrives one packet sooner. It extends selected runtimes beyond the ordinary {§worker-optimistic-settlement} cap before the next packet assembles. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
3026
3079
  - §exec-entry-sink **The entry() sink** implements {§executor-entry-sink} over ordinary scheme-owned entries. Core owns allocation, materialization, and persistence; executors receive only the returned resource address.
3027
3080
 
3028
3081
  | Input / effect | Consumer behavior |
@@ -3045,7 +3098,7 @@ body prefixes.
3045
3098
 
3046
3099
  - **Client disposition** ({§methods-proposal-resolve}) — a client interface delivers accept, reject, or cancel; AG-UI uses standard resume entries ({§agui-proposal-resolve}).
3047
3100
  - **Loop disposition** ({§proposal-disposition}) — core applies the exact automatic accept/reject before observational subscribers run; automatic policy is not an event listener or client fallback.
3048
- - §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait.
3101
+ - §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait. Indefinite is with respect to the clock alone: the wait ends with its loop. A loop whose signal aborts — its own timeout, `loop.cancel`, worker `KILL` — settles every proposal it is holding through {§proposal-cancel-aborts}, carrying the abort's reason as the outcome, because a cancelled loop is not a loop awaiting a decision.
3049
3102
 
3050
3103
  **The decision drives a one-way state transition** on `log_entries.state` (resolution is idempotent — `WHERE state='proposed'`, so a second resolution 404s):
3051
3104
 
@@ -3055,7 +3108,7 @@ body prefixes.
3055
3108
  | §proposal-reject-fails reject | `failed` | 400 | `rejected` | none — the action did not occur. |
3056
3109
  | §proposal-cancel-aborts cancel | `cancelled` | 499 | `loop_aborted` | none — the loop is abandoning. |
3057
3110
 
3058
- §proposal-outcome-terse-error A caller-supplied `outcome` overrides the default. On an **accept** it stays forensics-only; a **non-accept** carries it as the `rx`'s terse `error` token (`write_failed` / `rejected` / `timeout` — one word, never prose), because "the action didn't occur" without the mechanical why leaves the model acting on a phantom success (the fan-out dead-park: an ENOENT apply rendered as a mute 400).
3111
+ §proposal-outcome-terse-error A caller-supplied `outcome` overrides the default. On an **accept** it rides the result as the forensic `outcome` field; a **non-accept** is a Problem that carries the same `outcome` field (`write_failed` / `rejected` / `timeout` — one word) and names it in its detail, because "the action didn't occur" without the mechanical why leaves the model acting on a phantom success (the fan-out dead-park: an ENOENT apply rendered as a mute 400). A settlement the **harness itself** decided — nobody attending, no answer before a deadline, a loop or daemon ending while the proposal waited — also states that condition and an exit in its detail and `recovery`, because a reviewer's outcome is a reviewer's word but these have no author present to explain them; the one-word token stays as the forensic `outcome` either way.
3059
3112
 
3060
3113
  §proposal-proposed-hidden **A proposed row is invisible until it resolves.** A `state='proposed'` / 202 row is withheld from both packet materialization and `log/entry`; it surfaces exactly once after resolution, carrying its terminal status — models and clients see outcomes, never pending proposals.
3061
3114
 
@@ -3094,10 +3147,12 @@ issues; the same request remains pending and answerable. Cancellation requires n
3094
3147
  payload. Owner abort deletes the row and rejects the
3095
3148
  waiter with that owner's cancellation reason. An executor's waiter follows its
3096
3149
  execution signal, including KILL and deadline, not just its enclosing loop.
3150
+ Scheme and executor interaction requests may supply a narrower signal; Core
3151
+ composes it with the existing owner signal before registering the same waiter.
3097
3152
  Reconnect discovery intersects durable rows with live waiters; restart
3098
3153
  removes ownerless rows without fabricating cancellation, payload, or replay.
3099
3154
 
3100
- ### §proposal-ownership Loop disposition and client YOLO
3155
+ ### Loop disposition and client YOLO
3101
3156
 
3102
3157
  Side-effecting operations propose ({§exec}) and pause dispatch at 202 for an
3103
3158
  authority decision ({§engine-rails}, {§methods}). Automatic acceptance has two
@@ -3116,11 +3171,76 @@ only after authority crosses the client boundary.
3116
3171
 
3117
3172
  ### §proposal-disposition Settlement authority and precedence
3118
3173
 
3174
+ §loop-attendance **A loop says whether anyone is attending, and a wait nobody could end is
3175
+ never taken.** `LoopPolicy.attended` is the whole of it: `true` says an interactive partner is
3176
+ present, `false` declares an unattended loop. It is one field of the loop's complete policy, so
3177
+ its creator states it or leaves it to the panel ({§loop-policy-composition}); the client's
3178
+ `--auto` is exactly the statement `attended: false`. A fresh delegated loop inherits it with the
3179
+ rest of the policy ({§worker-delegation-inherits-policy}), so a child of a headless run is
3180
+ headless too.
3181
+
3182
+ Unattended, three things follow and nothing else does:
3183
+
3184
+ - **A proposal is never held for review.** `{ proposals: "review", attended: false }` is not a
3185
+ `LoopPolicy`: the schema refuses the pair, so no loop can persist it. The panel cannot produce
3186
+ it, because attendance picks which disposition knob answers. Only a creator's own statement
3187
+ can ask for it, and that is refused **400 `loop-policy-invalid`** naming the way out.
3188
+ - **No interactive partner is offered.** `ClientInteractions.request` refuses **501
3189
+ `loop-unattended`** instead of writing the request down and waiting. Every wiring funnels
3190
+ through that one request — the `question` runtime ({§question-tool}), the execution input
3191
+ bridge, the scheme interaction caps, and MCP elicitation — so one refusal covers them all. The
3192
+ `question` runtime's effect is `read`, so it is never proposal-gated and a disposition does
3193
+ nothing for it. The refusal is the asking executor's **own result**, never a thrown contract
3194
+ violation: the model has to read why it cannot ask.
3195
+
3196
+ Dispatch refuses it first, at the **loop ring** of the capability cascade: an unattended loop's
3197
+ own layer denies the `interact` access class ({§worker-tool-admission}), and that 403 names the
3198
+ ring, the reason and the recovery — a subtracted tool must say why it is gone and what to do
3199
+ instead. Every other ring is operator configuration and speaks for itself; the loop ring is the
3200
+ one the model can act on. The 501 at the interaction itself is the backstop for the paths that
3201
+ do not cross dispatch (MCP elicitation raised inside a tool call, the execution-input bridge).
3202
+ The ring reaches dispatch but not the reserved tree's listing, which is one artifact per
3203
+ workspace: an unattended model still sees the question document and learns at dispatch that it
3204
+ is refused (#770).
3205
+ - **A provider-recovery park becomes a conclusion** ({§provider-recovery}), carrying the
3206
+ provider's own exact Problem. Never a substituted "the model gave up".
3207
+
3208
+ **A park is a promise that something will restart it.** `LoopLifecycle.park` takes the waker
3209
+ by name; `null` says nothing will. Parking an unattended loop with no waker is a contract
3210
+ violation and throws, so a park site added later fails loudly on its first unattended run
3211
+ instead of idling until some caller's clock notices. It is a tripwire, not a fallback: the
3212
+ provider-recovery path concludes before reaching it.
3213
+
3214
+ Attendance never converts a legitimate wait that has a real waker — a `WAIT`, an open stream,
3215
+ a delegated child — into a termination. Those have wakers; a human question
3216
+ does not. A prompt prefix states a disposition, never an attendance: typing `?` asks for review,
3217
+ and an unattended loop refuses that statement rather than conjuring a reviewer.
3218
+
3219
+ §loop-policy-composition **A loop's policy is what its creator stated over what the panel
3220
+ says.** A creator — a client's `loop.run`, a schedule definition, a transport module — states
3221
+ any part of a policy as a `LoopPolicyRequest`, or nothing. The request stays exactly as stated
3222
+ until a fresh loop is persisted: an omitted field is no opinion, so a fold compares only what
3223
+ was said ({§methods-loop-run-fold-consistency}). `LoopPolicies.compose` then makes it whole,
3224
+ once. `PLURNK_SERVICE_ATTENDED` answers an unstated attendance, and the attendance picks which
3225
+ knob answers an unstated disposition: `PLURNK_SERVICE_PROPOSALS` for an attended loop,
3226
+ `PLURNK_SERVICE_UNATTENDED_PROPOSALS` for an unattended one, whose vocabulary has no `review`.
3227
+ Every panel state is therefore lawful, and an invalid knob fails boot by its name. No code,
3228
+ schema or column holds a default ({§operator-config-only-home}): `loops.policy` and
3229
+ `loops.max_turns` carry none, so every insert states both, and an administrative loop — a
3230
+ client's direct statements, the runtime's own narration — states the panel's policy like any
3231
+ other loop whose creator said nothing.
3232
+
3119
3233
  §loop-policy-effective-read `loops.policy` persists one complete immutable
3120
3234
  `LoopPolicy`; every runtime policy read validates that snapshot before use.
3121
3235
  Missing rows or invalid values fail with the owning loop coordinate and cause.
3122
3236
  Raw archival copies and forensic rendering do not interpret policy.
3123
3237
 
3238
+ The cascade's rings are `service`, `workspace` and, innermost, `loop`. The loop ring exists only
3239
+ for an unattended run and is purely subtractive like every other layer, so it can never widen what
3240
+ its workspace allows; a capability denial names the ring that refused. The operator's capability
3241
+ projection and the shared reserved-document materialization take no loop coordinate on purpose:
3242
+ those questions are about a workspace, not about one run.
3243
+
3124
3244
  `ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The persisted loop policy determines it exactly:
3125
3245
 
3126
3246
  | `policy.proposals` | Disposition |
@@ -3139,7 +3259,7 @@ Capability admission precedes this decision, so proposal disposition cannot gran
3139
3259
 
3140
3260
  ### §subscriptions Subscriptions
3141
3261
 
3142
- §subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. A failed TASK, worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation hook or database access is part of the plugin contract.
3262
+ §subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. Worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation hook or database access is part of the plugin contract.
3143
3263
 
3144
3264
  The durable row is lifecycle evidence and the lookup key, not a serialized callback. `subscriptions.open()` establishes both halves before yielding a composed `StreamSubscription`: an `AbortSignal` whose fused `notifyChunk` and terminal `close` methods are safe to retain without the operation's general `SchemeCtx`. `close(result, summary?, channelResults?)` validates one universal terminal producer result plus exact named channel overrides. One SQLite transition closes the subscription and installs each channel's terminal `producerResult`; its lifecycle state derives from that result. The transition then wakes the worker when appropriate and unregisters the live handle. `close_status` is a constrained relational projection of `close_result.status`, never an independent result, while `channel_results` preserves historical overrides after a later subscription replaces the channel's current evidence. A durable open row without a live handle is an explicit lifecycle failure, never a fabricated cancellation success. Channel state ({§channel-state}) + log entries ({§no-chunk-rows}) carry lifecycle.
3145
3265
 
@@ -3160,7 +3280,7 @@ live executor's current declaration.
3160
3280
 
3161
3281
  §subscriptions-fold-keeps-subscription A scoped KILL changes a log row's readable projection ({§log-kill-scope}), never the subscription registry. Curation of a streaming entry's log body leaves the live stream and its source running; it is not cancellation.
3162
3282
 
3163
- ### §chunk-accumulation Chunk accumulation
3283
+ ### Chunk accumulation
3164
3284
 
3165
3285
  §chunk-accumulation-chunks-accumulate SSE event types, WS message types, exec stdout/stderr each map to a named channel. Each stored channel carries `content`, `mimetype`, curation `weight`, and lifecycle `state` ({§channel-state}). The subscription registry owns durable subscription identity and process-local cancellation routing, not a second channel-state representation. Chunks accumulate into the channel as they arrive — not buffered until close.
3166
3286
 
@@ -3170,20 +3290,16 @@ live executor's current declaration.
3170
3290
 
3171
3291
  Model sees lifecycle events in the `log` section per turn.
3172
3292
 
3173
- ### §deep-slices Deep slices on demand
3174
-
3175
- ```` ```READ (https://feed.example/x#body) <N-M> ```` pulls a slice into a log row when the model wants a specific line-range of an SSE stream.
3176
-
3177
3293
  ### §stream-control Stream control and writes
3178
3294
 
3179
3295
  - **Cancel:** ```` ```KILL (https://feed.example/x) ```` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
3180
- - **Kill:** ```` ```KILL (sh:///ab3d5678) ```` — the model terminates the addressed workspace stream. This is stream control, not a write: the output scheme's `writableBy` never gates it. An already-killed stream answers 410; another terminal stream answers 409 with its recorded status ({§runtime-resource-binding}). A queued execution ({§exec-concurrency}) is cancelled the same way and never enters its executor.
3296
+ - **Kill:** ```` ```KILL (sh:///ab3d5678) ```` — the model terminates the addressed workspace stream. This is stream control, not a write: the output scheme's `writableBy` never gates it. A stream that already ended, killed or not, answers 200 with its recorded `terminalStatus`: the process is not running, which is what KILL asks for (#757); a stream that never existed answers 404 ({§runtime-resource-binding}). A queued execution ({§exec-concurrency}) is cancelled the same way and never enters its executor.
3181
3297
  - **WebSocket write:** ```` ```EDIT (wss://feed/x) ```` or ```` ```SEND (wss://feed/x) ```` with a body sends one whole text frame through the active owner. Either write can follow the opening READ in the same turn under {§op-execution-order}.
3182
3298
  - **Other stream write:** ```` ```SEND (…) ```` remains scheme-defined, including exec stdin.
3183
3299
 
3184
3300
  ### §stream-constraints Engine constraints
3185
3301
 
3186
- ONE engine-level constraint: **100 MiB char-length cap per channel body**. `CHECK (length(content) <= 104857600)` on `entry_channels.content` in `migrations/005_entries.sql`. Violations → SQLITE_CONSTRAINT; action-entry captures rejection at status 500.
3302
+ ONE engine-level constraint: **100 MiB char-length cap per channel body**. `CHECK (length(content) <= 104857600)` on `contents.content` and on an active stream's `entry_channel_rows.buffer` in `migrations/005_entries.sql` ({§content-store}). Violations → SQLITE_CONSTRAINT; action-entry captures rejection at status 500.
3187
3303
 
3188
3304
  §stream-constraints-engine-one-cap All other limits are extrinsic — providers (request size, model context, fetch timeouts), schemes (per-call validation), mimetypes (render budgets). Engine does not throttle, batch, rate-limit, or cap anything else.
3189
3305
 
@@ -3195,11 +3311,11 @@ The model is NOT a stream/event consumer — turn-based only; sees whatever's in
3195
3311
 
3196
3312
  ---
3197
3313
 
3198
- ## §storage Storage Model
3314
+ ## Storage Model
3199
3315
 
3200
3316
  SQLite (`node:sqlite`) with WAL mode and STRICT tables. Hand-written DDL; CI-aligned against grammar schemas.
3201
3317
 
3202
- ### §ddl DDL strategy
3318
+ ### DDL strategy
3203
3319
 
3204
3320
  No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, explicit `NOT NULL`, indexed query paths, deliberate FK `ON DELETE`/`ON UPDATE`, `WITHOUT ROWID` where access pattern warrants, generated columns, FTS5.
3205
3321
 
@@ -3213,10 +3329,11 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
3213
3329
  | §db-fk-indexes Foreign-key check paths | Every foreign-key column a delete, cascade, or parent replacement can check carries an index (partial where the column is nullable), and no registry statement's plan scans a growing table: `test/intg/schema-query-plans.test.ts` runs `EXPLAIN QUERY PLAN` over every `-- PREP` statement against the baseline and fails on a `SCAN` of a growing table, except statements that read a whole table by design (digest, startup recovery, whole-workspace listings, scheduled-loop claims). An index claim is a plan, never a grep of index names. |
3214
3330
  | §db-index-owners Every index has an owner | An explicit index earns its place one of three ways: a registry statement's plan uses it, its leading column is a foreign key whose check it serves, or it enforces uniqueness. The same test fails on any other index, naming it: an index nobody reads is a write on every insert. Duplicates of a `UNIQUE` constraint's own index and sort-only indexes no plan selects were removed on this rule; a column no statement reads (`symbol_refs.col`, `ambient_events.created_at`) is not stored. |
3215
3331
  | §db-maintenance-optimize Statistics at shutdown | The daemon's last database step before the caller closes SQLite is `PRAGMA optimize` on the writer (`maintenance_optimize`), so `sqlite_stat1` reflects tables the connection planned against, bounded by SQLite's own analysis limit; a failure there is a reported shutdown error, never silent. Retention runs before it under the operator's policy ({§retention-policy}); no explicit checkpoint and no periodic `ANALYZE` run. |
3216
- | §retention-policy Retention is the operator's policy; information is kept by default | `Retention` (`src/server/Retention.ts`, statements in `Retention.sql`) reads seven knobs from `.env.defaults` once at daemon construction and runs four set statements in dependency order — on `PLURNK_SERVICE_RETENTION_INTERVAL_MS` cadence while the daemon runs (0 = shutdown only) and once more at shutdown before `PRAGMA optimize`. `PLURNK_SERVICE_RETAIN_PACKET_TURNS` (-1 = every packet) and `PLURNK_SERVICE_RETAIN_PACKET_MS` (-1 = no age limit) retire a completed turn's packet composition (`turn_sections`, {§packet-items}) once it is beyond the newest N packet-bearing turns of its loop or older than the age; the turn, its bag, its log rows and its accounting stay, and an open turn is never retired. `PLURNK_SERVICE_COLLECT_PACKET_ITEMS` (1) collects items no composition references. `PLURNK_SERVICE_COLLECT_DERIVATIONS` (1) collects derivations no channel, turn source, or log row cites — superseded editions — with their symbols (cascade) and their full-text shadow (`derivations_delete_fts`, a process trigger beside the FTS statements, on every delete path). `PLURNK_SERVICE_RETAIN_RESPONSE_TURNS` (-1) and `PLURNK_SERVICE_RETAIN_RESPONSE_MS` (-1) retire a settled call's response body (`model_call_responses`) once it is beyond the newest N body-bearing calls of its loop or its turn is older than the age; the call's identity, failure, capacity, admission and accounting stay, and the digest renders such a call request-only. Under the shipped defaults nothing that is information leaves; only what no row references. A malformed knob refuses daemon construction. Witness: `test/intg/retention.test.ts`. |
3332
+ | §db-space-reclamation The daemon keeps its own file healthy | `PLURNK_SERVICE_AUTO_VACUUM` (`incremental`, the default, or `none`) names the mode the daemon keeps its file in. At start, before any drain, a database in another mode is converted (set the mode, one `VACUUM`, which rewrites the file and needs free disk about its size) and the journal says so with page counts before and after. Under `incremental`, every retention pass ends by stepping `PRAGMA incremental_vacuum` to completion once free pages reach `PLURNK_SERVICE_RECLAIM_MIN_FREE_BYTES` (0, the default, = every pass), and reports `reclaimedPages`; below the floor, free pages stay for SQLite to reuse. Under `none` the file never shrinks and freed pages are reused. No operator step is involved beyond the knobs. The WAL stays bounded by SQLite's automatic checkpoint (#764). |
3333
+ | §content-store Every body is stored once | `contents` holds each settled body once, addressed by its SHA-256, however many channels, workspaces, forks or derivations carry it; rows are immutable. `entry_channel_rows` points a settled channel at its body and keeps an active stream's body as a private buffer until it settles, when it is interned. Every reader and writer uses the `entry_channels` view, whose `INSTEAD OF` triggers intern bodies, refuse a bound `content_hash` that is not the content's, and write each column group only when it changed, so a search attachment is never a representation write. SQLite counts no changes for a view, so a write that must know whether its channel exists returns the channel's name; an outer join cannot flatten the view, so the two statements that need one read `entry_channel_rows` and `contents` directly. `derivation_fts` is an external-content index over `derivation_texts` (a derivation joined to its body); `derivations.content_id` names the indexed text, and the triggers in `_entry-fts.sql` move the index with it and forget it on delete. A body no channel holds and no derivation indexes is collected by retention under `PLURNK_SERVICE_COLLECT_CONTENTS` (1). Witnesses: `test/intg/retention.test.ts`, `test/intg/entries.test.ts`, `test/intg/fulltext-index.test.ts`. |
3334
+ | §retention-policy Retention is the operator's policy; information is kept by default | `Retention` (`src/server/Retention.ts`, statements in `Retention.sql`) reads ten knobs from `.env.defaults` once at daemon construction (the two storage knobs are {§db-space-reclamation}) and runs four set statements in dependency order — on `PLURNK_SERVICE_RETENTION_INTERVAL_MS` cadence while the daemon runs (0 = shutdown only) and once more at shutdown before `PRAGMA optimize`. `PLURNK_SERVICE_RETAIN_PACKET_TURNS` (-1 = every packet) and `PLURNK_SERVICE_RETAIN_PACKET_MS` (-1 = no age limit) retire a completed turn's packet composition (`turn_sections`, {§packet-items}) once it is beyond the newest N packet-bearing turns of its loop or older than the age; the turn, its bag, its log rows and its accounting stay, and an open turn is never retired. `PLURNK_SERVICE_COLLECT_PACKET_ITEMS` (1) collects items no composition references. `PLURNK_SERVICE_COLLECT_CONTENTS` (1) collects stored bodies nothing holds ({§content-store}), after the collectors that release them. `PLURNK_SERVICE_COLLECT_DERIVATIONS` (1) collects derivations no channel, turn source, or log row cites — superseded editions — with their symbols (cascade) and their full-text shadow (`derivations_delete_fts`, a process trigger beside the FTS statements, on every delete path). `PLURNK_SERVICE_RETAIN_RESPONSE_TURNS` (-1) and `PLURNK_SERVICE_RETAIN_RESPONSE_MS` (-1) retire a settled call's response body (`model_call_responses`) once it is beyond the newest N body-bearing calls of its loop or its turn is older than the age; the call's identity, failure, capacity, admission and accounting stay, and the digest renders such a call request-only. Under the shipped defaults nothing that is information leaves; only what no row references. A malformed knob refuses daemon construction. Witness: `test/intg/retention.test.ts`. |
3217
3335
 
3218
- - **Schema-alignment test**: loads `@plurnk/plurnk-contracts/schema/*.json`, parses DDL via `node:sqlite` introspection, asserts every required schema field has a corresponding `NOT NULL` column. Contract drift fails CI.
3219
- - DDL = storage truth; JSON Schemas = wire truth. Tested-aligned, allowed to differ where ergonomics demand.
3336
+ - DDL = storage truth; JSON Schemas = wire truth. They are allowed to differ where ergonomics demand.
3220
3337
  - §entry-identity-no-null **Identity components are never NULL.** `(workspace_id, scheme, authority, pathname)` is a unique key. `workspace_id` references the workspace directly with cascading deletion. Namespace schemes use empty authority; resource schemes retain their canonical authority. File members use nonempty `scheme="file"` and render as bare paths. Registration refuses `storedScheme: null`.
3221
3338
 
3222
3339
  ### §sql-ts-boundary SQL/TS responsibility boundary
@@ -3336,10 +3453,10 @@ service manifest edit.
3336
3453
 
3337
3454
  ---
3338
3455
 
3339
- ## §grammar Grammar Dependency
3456
+ ## Grammar Dependency
3340
3457
 
3341
3458
  Core consumes the language, schemas, and generated types under
3342
- {§contract-authority} and {§contract-representations}. Provider emissions cross
3459
+ {§contract-representations}. Provider emissions cross
3343
3460
  {§emission-admission}; admitted programs execute through
3344
3461
  {§turn-ops-admission-path}. Core owns execution and persisted state, not a second
3345
3462
  language definition.
@@ -3358,7 +3475,7 @@ and is ignored rather than resolved against the working directory.
3358
3475
  |---|---|---|
3359
3476
  | Configuration | `$XDG_CONFIG_HOME` (default `~/.config`) | `plurnk/.env`, `plurnk/AGENTS.md` |
3360
3477
  | Durable user data | `$XDG_DATA_HOME` (default `~/.local/share`) | `plurnk/plurnk.db` and SQLite sidecars |
3361
- | Persistent operational state | `$XDG_STATE_HOME` (default `~/.local/state`) | Reserved; no directory is created without an owned artifact. |
3478
+ | Persistent operational state | `$XDG_STATE_HOME` (default `~/.local/state`) | On-demand workspace/module directories ({§module-workspace-directory}). |
3362
3479
  | Reproducible cache | `$XDG_CACHE_HOME` (default `~/.cache`) | Reserved; no directory is created without an owned artifact. |
3363
3480
  | Shared global Agent Skills | User home | `.agents/skills/<name>/SKILL.md` |
3364
3481
 
@@ -3384,6 +3501,23 @@ Node's pre-script env-file form and the executable's post-script form share the
3384
3501
 
3385
3502
  §operator-config-env-defaults **Every package owns its knobs — `.env.defaults` is the standard.** Each package in the daemon's ecosystem — internal or third-party — ships a `.env.defaults` at its package root declaring its own knobs; the file is the package's configuration reference, traveling in the tarball and changing with the code that reads it. At boot the daemon assembles every installed member's file into one floor (membership = the `@plurnk/*` scope or a `plurnk` package.json field, gated by `PLURNK_PLUGINS_TRUSTED_ONLY` with discover()'s exact semantics) and applies it set-if-unset under every operator source. `plurnk-service config defaults` renders the same complete, owner-labelled aggregate to stdout on demand, preserving comments and optional declarations without persisting a second copy or exposing effective secret values. A key claimed by two packages fails boot naming both. With the reader-declares discipline, each key has one implementation and one defaults owner.
3386
3503
 
3504
+ §operator-config-only-home **The cascading environment is the only home for a choice.** The principle and its reasons are ARCHITECTURE.md's (*Configuration authority*); this is what `scripts/env-surface-policy.mjs` enforces in `root:lint`, over the source Git tracks:
3505
+
3506
+ | Rule | What it refuses |
3507
+ |---|---|
3508
+ | `undeclared` | a knob read that no panel declares, live or as an optional knob; a computed name is covered by one declared example of its family |
3509
+ | `fallback` | a read that carries its own value |
3510
+ | `reader-fallback` | a reader whose signature accepts one, so a caller could state what the panel did not |
3511
+ | `default-constant` | a constant named `DEFAULT_*`: *default* is a word reserved for a value on the panel |
3512
+ | `tunable` | a numeric constant whose own name says duration, size, count or pacing, unless `scripts/env-surface-mechanism.json` registers why it is mechanism |
3513
+ | `timer-literal` | a bare number handed to a timer or a deadline; it is named or read from the panel, and has no register |
3514
+ | `dead-knob` | a live declaration nothing consumes |
3515
+ | `retired-declared` | a retired key still declared; a retired key is named only by the code that refuses it |
3516
+ | `duplicate-owner` | a key two packages declare |
3517
+ | `test-floor` | a package that ships a panel and tests off it |
3518
+
3519
+ Reading the system environment directly is the mechanism and never a finding. The allowance file is a ratchet — new debt is refused, and so is a paid debt left on the books — and it is empty. The register is not a debt: it is the reviewed list of deliberate non-knobs, each with its reason, and an entry whose number is gone is refused.
3520
+
3387
3521
  §operator-config-source-errors An optional member file may be absent; other read failures surface with the
3388
3522
  owning package and original cause, never as an incomplete successful catalog.
3389
3523
 
@@ -3399,36 +3533,37 @@ complete installed option catalog.
3399
3533
 
3400
3534
  Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` optionally declares a friendly route and tuning scope; `PLURNK_MODEL=<selector>` selects either that alias or an exact provider/model route. `PLURNK_MODEL_CHILD=<selector>` uses the same vocabulary for the default child provider; unset means inherit the spawning loop's provider. Operator selections and alias declarations live in `.env`, not `.env.defaults`.
3401
3535
 
3402
- | Var | Default | Purpose |
3403
- |-------------------------------------------------------------|---------|---------|
3404
- | `PLURNK_SERVICE_DB_PATH` | `$XDG_DATA_HOME/plurnk/plurnk.db` | SQLite file path; an explicit non-empty value overrides the derived default. |
3405
- | `PLURNK_HOST` | `127.0.0.1` | Bind address for the listener. Local-only by default. |
3406
- | `PLURNK_PORT` | `1066` | TCP port for THE client surface — the AG-UI+ listener (the plurnk-agui plugin module binds it at boot). Production is single-listener. |
3407
- | §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | `1` | Hard service ceiling: only `1` admits Git membership and status; every other value denies them. |
3408
- | §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | `root` | Hard file-creation ceiling: `none < root < namespace`. `none` denies new filesystem files, `root` admits only paths inside `project_root`, and `namespace` also admits canonical outside-root paths. Existing-member writes are unaffected. |
3409
- | `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | `104857600` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
3410
- | `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator inference-turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts completed model/inference turns cumulatively across every `202` park/resume; `_plurnk`, client, and plugin turns remain chronology but consume none of this allowance. |
3411
- | `PLURNK_SERVICE_MAX_COMMANDS` | `-1` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. The final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
3412
- | §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | `86400000` | Positive ms of cumulative active execution per loop ({§loop-execution-allowance}); excludes parked/queued time. Snapshotted on first execution, retained across wakes. Exhaustion aborts in-flight work and terminates `504 loop_timeout`, including a stuck provider call. |
3413
- | `PLURNK_SERVICE_PROVIDER_RECOVERY` | `900000` | ms a turn keeps re-issuing its provider call after a recoverable provider failure before the loop parks ({§provider-recovery}); `0` parks at once. |
3414
- | `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | `5000` | First recovery delay (ms); doubles per failure, capped at twelve times itself ({§provider-recovery}). |
3415
- | `PLURNK_SERVICE_MAX_STRIKES` | `3` | Consecutive turn-contract strike threshold ({§engine-rails}). |
3416
- | `PLURNK_SERVICE_EMISSION_ATTEMPTS` | `3` | Completed provider responses allowed beneath one engine turn before frame admission is exhausted. Bounded interior operation errors are admitted without spending this budget. Exhaustion contributes one frame-contract strike under {§invalid-emission-attempts}. |
3417
- | `PLURNK_SERVICE_PREVIEW_LINES` | `16` | Maximum lines in automatic text previews and markerless READs ({§body-projection}). |
3418
- | `PLURNK_SERVICE_PREVIEW_CHARS` | `2560` | Independent Unicode code-point bound on the same previews, with CRLF treated as one indivisible separator ({§body-projection}). |
3419
- | `PLURNK_SERVICE_PROMPT_PROJECTION` | `25%` | Aggregate curation-weight share of the provider-derived input capacity available to automatic prompt-body projection ({§prompt-projection}); alias-scoped overrides are supported. |
3420
- | `PLURNK_SERVICE_LINE_ANCHOR_CONTEXT_LINES` | `2` | Complete neighboring lines hashed on each side of a model-facing line anchor ({§line-anchors}). |
3421
- | `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | `2` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
3422
- | `PLURNK_SERVICE_MIN_CYCLES` | `3` | Min repetitions before cycle detection fires ({§engine-rails}). |
3423
- | `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | `4` | Max period length cycle detection examines ({§engine-rails}). |
3424
- | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
3425
- | `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | `32768` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
3426
- | `PLURNK_SERVICE_FILES_ITEMS` | `-1` | Turn-0 catalog preview. Folder-capable schemes render a one-level `*` map with `dir/**` rollups; kernel docs remain recursive and explicitly complete. `-1` = markerless first pages; positive `N` explicitly caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
3427
- | `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` | `namespace` | Ceiling for a model's `members` definitions in the lattice `none < root < namespace`; `none` refuses every model definition ({§members-model-scope}). |
3428
- | `PLURNK_SERVICE_EXEC_CONCURRENCY` | `12` | Executions admitted at once per workspace; the rest queue FIFO with `202 queued` receipts; `-1` unbounded ({§exec-concurrency}). |
3429
- | `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | (empty — waits indefinitely) | Finite positive milliseconds before cancellation with outcome `timeout`; empty waits, and every other explicit value fails ({§proposal-timeout-cancels}). |
3430
- | §operator-config-worker-warm `PLURNK_SERVICE_WORKSPACE_WARM_MS` | `900000` | Milliseconds a lease-free workspace Functionality snapshot remains warm; `0` cools without grace and `-1` disables time-based cooling ({§module-workspace-residency}). |
3431
- | `PLURNK_SERVICE_WORKSPACE_WARM_MAX` | `2` | Maximum lease-free workspace Functionality snapshots retained process-wide; `0` retains none and `-1` disables the idle-LRU bound ({§module-workspace-residency}). |
3536
+ Each knob's value lives on its panel and nowhere else (`plurnk-service config defaults` prints them all); this table says what the service's knobs mean.
3537
+
3538
+ | Var | Purpose |
3539
+ |---|---|
3540
+ | `PLURNK_SERVICE_DB_PATH` | SQLite file path; an explicit non-empty value overrides the derived default. |
3541
+ | §operator-config-shared-keys `PLURNK_HOST`, `PLURNK_PORT` | The listener's bind address and TCP port — THE client surface, the AG-UI+ listener the plurnk-agui module binds at boot; production is single-listener. **A key the daemon and its clients both read has a shared owner**: `@plurnk/plurnk-contracts` declares these two and the optional `PLURNK_AGUI_URL` on its own panel, the one package every side depends on. The daemon folds it like any installed member's, a client folds it beneath its own, and so neither holds the other's default. The service's `--host` and `--port` flags are generated from that panel. |
3542
+ | §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | Hard service ceiling: only `1` admits Git membership and status; every other value denies them. |
3543
+ | §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | Hard file-creation ceiling: `none < root < namespace`. `none` denies new filesystem files, `root` admits only paths inside `project_root`, and `namespace` also admits canonical outside-root paths. Existing-member writes are unaffected. |
3544
+ | `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
3545
+ | `PLURNK_SERVICE_MAX_TURNS` | Operator inference-turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts completed model/inference turns cumulatively across every `202` park/resume; `_plurnk`, client, and plugin turns remain chronology but consume none of this allowance. |
3546
+ | `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. The final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
3547
+ | §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | Positive ms of cumulative active execution per loop ({§loop-execution-allowance}); excludes parked/queued time. Snapshotted on first execution, retained across wakes. Exhaustion aborts in-flight work and terminates `504 loop_timeout`, including a stuck provider call. |
3548
+ | `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms a turn keeps re-issuing its provider call after a recoverable provider failure before the loop parks ({§provider-recovery}); `0` parks at once. |
3549
+ | `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | First recovery delay (ms); doubles per failure up to `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX` ({§provider-recovery}). |
3550
+ | `PLURNK_SERVICE_MAX_STRIKES` | Consecutive turn-contract strike threshold ({§engine-rails}). |
3551
+ | `PLURNK_SERVICE_EMISSION_ATTEMPTS` | Completed provider responses allowed beneath one engine turn before frame admission is exhausted. Bounded interior operation errors are admitted without spending this budget. Exhaustion contributes one frame-contract strike under {§invalid-emission-attempts}. |
3552
+ | `PLURNK_SERVICE_PREVIEW_LINES` | First page of every markerless retrieval, in the projection's own units, and the head bound of an automatic preview ({§markerless-first-page}, {§body-projection}). |
3553
+ | `PLURNK_SERVICE_PREVIEW_CHARS` | Independent Unicode code-point bound on the same previews, with CRLF treated as one indivisible separator ({§body-projection}). |
3554
+ | `PLURNK_SERVICE_PROMPT_PROJECTION` | Aggregate curation-weight share of the provider-derived input capacity available to the automatic projection of arrivals from outside the workspace ({§message-projection}); alias-scoped overrides are supported. |
3555
+ | `PLURNK_SERVICE_LINE_ANCHOR_CONTEXT_LINES` | Complete neighboring lines hashed on each side of a model-facing line anchor ({§line-anchors}). |
3556
+ | `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
3557
+ | `PLURNK_SERVICE_MIN_CYCLES` | Min repetitions before cycle detection fires ({§engine-rails}). |
3558
+ | `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | Max period length cycle detection examines ({§engine-rails}). |
3559
+ | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | Initial forensic witness output allowance ({§digest-requiem}). |
3560
+ | `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
3561
+ | `PLURNK_SERVICE_FILES_ITEMS` | Turn-0 catalog preview. Folder-capable schemes render a one-level `*` map with `dir/**` rollups; kernel docs remain recursive and explicitly complete. `-1` = markerless first pages; positive `N` explicitly caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
3562
+ | `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` | Ceiling for a model's `members` definitions in the lattice `none < root < namespace`; `none` refuses every model definition ({§members-model-scope}). |
3563
+ | `PLURNK_SERVICE_EXEC_CONCURRENCY` | Executions admitted at once per workspace; the rest queue FIFO with `202 queued` receipts; `-1` unbounded ({§exec-concurrency}). |
3564
+ | `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | Finite positive milliseconds before cancellation with outcome `timeout`; empty waits, and every other explicit value fails ({§proposal-timeout-cancels}). |
3565
+ | §operator-config-worker-warm `PLURNK_SERVICE_WORKSPACE_WARM_MS` | Milliseconds a lease-free workspace Functionality snapshot remains warm; `0` cools without grace and `-1` disables time-based cooling ({§module-workspace-residency}). |
3566
+ | `PLURNK_SERVICE_WORKSPACE_WARM_MAX` | Maximum lease-free workspace Functionality snapshots retained process-wide; `0` retains none and `-1` disables the idle-LRU bound ({§module-workspace-residency}). |
3432
3567
 
3433
3568
  Every core knob listed is enforced at its owning read site; `.env.defaults` is the authoritative default ({§operator-config-env-defaults}). Provider, scheme, executor, mimetype, and client-interface knobs are documented by their owning packages and appear in the assembled catalog.
3434
3569
 
@@ -3449,11 +3584,11 @@ template both ways: every `PLURNK_SERVICE_*` the service reads has a
3449
3584
  declared `PLURNK_SERVICE_*` is read. A half-landed rename therefore fails a test
3450
3585
  instead of a user's boot, and a dead knob cannot ship.
3451
3586
 
3452
- §operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to the safe default model plus gate-wide service posture: a local model, complete catalog orientation, automatic Git membership when the operator ceiling permits Git, ambient operator-file docs/packet notes cleared, and `PLURNK_EXECS_QUESTION=0` for unattended runs. The ordinary executor switch removes the question tool and its teaching; an explicit override can opt into an attended drill. Configuration with a narrower or variable owner stays outside it:
3587
+ §operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to gate-wide service posture that is identical on every machine: complete catalog orientation, automatic Git membership when the operator ceiling permits Git, ambient operator-file docs/packet notes cleared, ambient MCP selections and schedules disabled, and `PLURNK_EXECS_QUESTION=0` for unattended runs. The ordinary executor switch removes the question tool and its teaching; an explicit override can opt into an attended drill. Configuration with a narrower or variable owner stays outside it:
3453
3588
 
3454
3589
  | Owner | Configuration |
3455
3590
  |---|---|
3456
- | `.env.test` | Safe default model selection and universal real-model gate posture, with no alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
3591
+ | `.env.test` | Universal real-model gate posture, with no model selection, alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
3457
3592
  | Live/demo scripts | The repository policy path and runner topology. |
3458
3593
  | Benchlets | Their snapshotted policy, workspace restrictions, and task-specific exceptions; direct env wins over the profile. |
3459
3594
  | Operator env/shell | Model alias declarations and explicit selection overrides, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
@@ -3631,9 +3766,22 @@ flowchart LR
3631
3766
  | §module-action-registration `registerModuleAction({ name, scope, inputSchema, outputSchema, handler })` | Adds one non-empty, extension-unique action with resolvable JSON Schemas. `scope` is exactly `worldless`, `workspace`, or `worker`; the handler receives schema-validated params and a separate matching context. Scoped contexts contain trusted bound identifiers, never client parameters. A client-interface module decides whether and how the name becomes public, validates successful output, and owns collisions with its built-ins. |
3632
3767
  | §module-workspace-provider `registerWorkspaceCapabilityProvider(namespaceOwner, provider)` | Registers one extension-unique Functionality provider. `activate({ workspaceId, retain })` reconstructs the workspace snapshot; idempotent `deactivate({ workspaceId })` releases process resources. Core coalesces demand and supplies residency leases for work that outlives its caller. |
3633
3768
  | §module-workspace-state `readWorkspaceModuleState(workspaceId, namespaceOwner)` | Reads one nullable JSON state value per workspace and provider. Core owns storage and lifecycle; the provider owns its schema. Store symbolic credential references, not copied secrets. A worker-scoped family's coordinator reads and replaces the same shape per worker in `worker_module_state` ({§functionality-scope}). |
3769
+ | `readWorkspaceEnvironment(workspaceId)` | Captures the workspace env layer ({§workspace-env}) and returns its composer. No argument uses admitted host values; a supplied environment supplies a module's reference-resolution context. Both apply the same captured values and masks, without worker overrides. |
3770
+ | §module-workspace-directory `workspaceStateDirectory(workspaceId, namespaceOwner)` | Returns and creates the module's absolute operational-state directory under the daemon's XDG state home. Core owns path resolution and a stable random workspace storage key in its own `workspace_module_state` row. The key survives workspace renames and daemon restarts; independently created workspaces, including in other databases, receive different keys. The module owns its contents and child-directory lifetimes. |
3634
3771
  | §module-functionality-adapter `registerFunctionalityAdapter(adapter)` | Registers one family beneath the shared coordinator ({§functionality-coordinator}). |
3635
3772
  | §module-workspace-capabilities `replaceWorkspaceCapabilities({ workspaceId, namespaceOwner, state, runtimes })` | Atomically replaces one provider's durable state and runtime/scheme snapshot at the workspace operation boundary. Namespace claims are validated before mutation. Failure restores the prior state and publication. |
3636
3773
 
3774
+ Module directory allocation is lazy, atomic in SQLite, and independent of the
3775
+ project root, daemon CWD, and workspace/worker environment overrides. New
3776
+ directories use mode `0700`; existing permissions are not rewritten. Module
3777
+ names occupy a single encoded path component. Missing workspaces, invalid
3778
+ stored keys, and filesystem failures are errors, never a fallback to CWD.
3779
+ Allocated state is not erased on cooling, disable, removal, or shutdown: its
3780
+ contents may be persistent or referenced by retained results. Deleting a
3781
+ workspace forgets its storage key through the existing foreign key; old disk
3782
+ state is not reassigned or automatically purged. A database copy preserves its
3783
+ storage identities; the directory is operational state, not a backup of it.
3784
+
3637
3785
  §workspace-environment-sharing **The workspace owns its shared environment.**
3638
3786
  Workers own their logs; delegation retains its existing lifecycle.
3639
3787
  Creating, attaching, forking, cancelling, or deleting a worker does not create,
@@ -3692,7 +3840,7 @@ The version-1 baseline table `workspace_module_state` stores one JSON value
3692
3840
  per `(workspace_id, namespace_owner)`. It is configuration, not an executable
3693
3841
  registry. Deleting the workspace cascades its state; worker lifecycle does not.
3694
3842
 
3695
- ## §functionality Workspace Functionality
3843
+ ## Workspace Functionality
3696
3844
 
3697
3845
  §functionality-coordinator **One coordinator owns the common lifecycle.**
3698
3846
  Agent Skills, MCP, outbound A2A agents, and membership are adapters beneath
@@ -3727,14 +3875,27 @@ failure aborts; cooling tears down. Protocol continuations remain ordinary
3727
3875
  module actions. Optional `forget` releases an installed or provisioned
3728
3876
  definition before removal; failure rejects removal ({§skills-remove}).
3729
3877
 
3730
- §env-functionality **Environment is the fourth family, owned per Worker.** Its two origins
3731
- are the ambient names the operator's ceiling admits ({§exec-env-scoped}, service origin, enabled
3732
- until a Worker disables one for itself) and the Worker's own entries (worker origin). `add` takes
3878
+ An adapter may expose a `scheme` facet beneath its family's runtime namespace
3879
+ ({§runtime-resource-binding}). A facet claims a path subtree and is the scheme's
3880
+ whole live half there: READ and FIND preparation, FIND, SEND, WAIT and KILL are
3881
+ its own wherever it implements them. A claimed KILL the facet does not implement
3882
+ is the ordinary entry KILL ({§stream-control}); an unclaimed coordinate keeps the
3883
+ stored-execution behaviour, SEND to a process included. Where its resources are
3884
+ not shaped like the executor's output, the facet states their representation —
3885
+ resource authority, channels, the default channel — and that manifest governs
3886
+ every claimed coordinate: its address, its fragmentless READ, the channel a
3887
+ subscription publishes. An adapter states the `traits` of its runtime — `web`
3888
+ for a family that reaches the network — so {§capability-admission} selects its
3889
+ manager and its resources alike.
3890
+
3891
+ §env-functionality **Environment is a scoped family.** Ambient names admitted by the
3892
+ operator's ceiling ({§exec-env-scoped}, service origin) precede workspace defaults and
3893
+ worker overrides ({§workspace-env}). `add` takes
3733
3894
  the name as the alias and `{ "value": "…" }` as the definition, used verbatim with no
3734
- interpolation. `disable` withdraws a name from the Worker's spawns while retaining it, which is
3735
- how `CI=1` goes away for one Worker without an operator change; `remove` forgets a Worker's own
3736
- entry and a same-name service baseline reappears disabled, so removal never silently changes what
3737
- the next spawn sees. Service definitions are disable-only.
3895
+ interpolation. `disable` withholds a name in the selected scope while retaining it;
3896
+ `remove` forgets a locally-owned entry and a same-name lower baseline reappears
3897
+ disabled, so removal never silently changes what the next spawn sees. Definitions
3898
+ from a lower layer are disable-only in the current scope.
3738
3899
 
3739
3900
  `list` projects effective values with their origin. Values are shown: the ceiling is the security
3740
3901
  boundary, not the projection, and any admitted name is already readable by every command the
@@ -3755,23 +3916,24 @@ name with its documentation and an empty value ({§exec-env-scoped}: referred to
3755
3916
  read). `configuration` is refused: a client's own environment contributing candidates would be a
3756
3917
  second door past the ceiling.
3757
3918
 
3758
- The family publishes no runtimes. An environment is read at the spawn that uses it, never held
3759
- resident, so it never enters the warmed capability snapshot ({§module-workspace-residency}).
3919
+ The family publishes no process runtimes. Its values are read at the spawn that uses them,
3920
+ not from a live process or a cached worker environment.
3760
3921
 
3761
- §functionality-scope **A family declares who owns its definitions.** Skills, MCP, members
3922
+ §functionality-scope **A family declares its supported scopes.** Skills, MCP, members
3762
3923
  and outbound A2A describe what exists in a **workspace**: a capability, resident or installable,
3763
3924
  that every Worker there shares. Environment describes how one **Worker** works — context rather
3764
- than capability — so its definitions are owned per Worker. The adapter declares `scope`
3765
- (absent means workspace) and the coordinator keys durable state and the locally-owned `origin`
3925
+ than capability — with worker overrides above workspace defaults. The adapter declares
3926
+ `scopes` (absent means `["workspace"]`; the first is the model default), and the
3927
+ coordinator keys durable state and the locally-owned `origin`
3766
3928
  by it: a workspace-scoped family's own entries carry origin `workspace`, a worker-scoped
3767
3929
  family's carry `worker`. Origin names ownership, never scope, so a projection never claims the
3768
3930
  workspace set a value one Worker set for itself. Nothing else in the contract varies: the six
3769
3931
  verbs, the two projections, enabledness, and the service-baseline rules are one implementation
3770
3932
  across every family, which is what keeps their idioms from drifting apart.
3771
3933
 
3772
- A worker-scoped family projects `worker.<family>.<verb>` in place of
3773
- `workspace.<family>.<verb>`; the action's context names the Worker, as every execution
3774
- does. Its durable value is the same shape per (worker, family) in `worker_module_state`, read
3934
+ A family projects `<scope>.<family>.<verb>` for each supported scope. The action's
3935
+ context binds that scope; a worker-scoped action also names the Worker. Its durable
3936
+ value is the same shape per (worker, family) in `worker_module_state`, read
3775
3937
  at each verb and at each spawn rather than held in the workspace snapshot. Its `list` and
3776
3938
  mutations serialize on the Worker's own lane and take no workspace exclusivity: nothing
3777
3939
  resident changes, and the next spawn reads the state, so a Worker shapes its own environment
@@ -3791,8 +3953,8 @@ option lands as the child's own entries through `add`, after the copy ({§env-op
3791
3953
  is stored under the provider namespace in `workspace_module_state`; a
3792
3954
  worker-scoped family ({§functionality-scope}) stores the same value per worker
3793
3955
  and family in `worker_module_state`.
3794
- A `service` entry persists enabledness; a `workspace` or `worker` entry persists
3795
- its exact definition. Active, unavailable, and authorization-required are preparation
3956
+ A locally-owned entry persists its exact definition; a lower-layer entry persists
3957
+ only enabledness, never a copied value. Active, unavailable, and authorization-required are preparation
3796
3958
  outcomes, not durable desired state. The configuration cascade contributes
3797
3959
  defaults; one workspace snapshot is effective authority.
3798
3960
 
@@ -3829,6 +3991,10 @@ binds that Worker to the manager at the operation, so the published manager
3829
3991
  stays one per workspace and the executor framework's arguments carry no
3830
3992
  identity ({§functionality-scope}).
3831
3993
 
3994
+ Expected adapter failures retain their exact status and Problem in both client
3995
+ actions and the model operation's stream/result ({§problem-error-carrier}). An
3996
+ unexpected exception remains an executor fault, not a managed refusal.
3997
+
3832
3998
  §functionality-document-body **A family's teaching is an authored file beneath
3833
3999
  its generated header.** The adapter names its package directory (`docsDir`);
3834
4000
  that package's `docs/<family>.md` is read once, by the same rule runtimes use
@@ -3871,7 +4037,7 @@ Core's behavior behind them.
3871
4037
  | §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)`; `cancelWorker({ workspaceId, workerId, reason? })` | `cancelDrain` begins durable structured cancellation and reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. The ownership-bounded `cancelWorker` awaits that same tree cancellation and stream reap, so an exterior protocol can project the settled durable result without polling or fabricating state. |
3872
4038
  | §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, statements })` | Dispatches already-parsed grammar statements as one client action in one administrative loop in the client worker, executing in the workspace's Functionality ({§actor-boundary-attached-functionality}). Every statement is an ordered client/operation turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep its turn, loop, and action promise open until resolution. Core exposes no per-op method family. |
3873
4039
  | Client observation | `look({ workspaceId, workerId, statement, perspectiveWorkerId? })` | Runs an already-parsed READ through the full resolver in the workspace's Functionality without a log row. A non-READ statement is rejected ({§op-look}). |
3874
- | §methods-log-read Reads | `readLog({ workspaceId, workerId, ...coordinate })` | Ownership-checks the worker, then reads by ids, recency, or the complete `loopSeq`/`turnSeq`/`sequence` display coordinate. `limit` defaults to 100 and is capped at 1000. |
4040
+ | §methods-log-read Reads | `readLog({ workspaceId, workerId, ...coordinate })` | Ownership-checks the worker, then reads by ids, recency, or the complete `loopSeq`/`turnSeq`/`sequence` display coordinate. An omitted `limit` is `PLURNK_SERVICE_LOG_READ_PAGE`, and any `limit` is capped at `PLURNK_SERVICE_LOG_READ_MAX`. |
3875
4041
  | §methods-entry-read Reads | `readEntry({ workspaceId, workerId, target, channel?, offset? })` | Resolves the selector from that worker's perspective and returns {§entry-read-result}, either complete or as one channel suffix, without creating action evidence. |
3876
4042
  | Providers | `listProviders()` | Lists configured aliases with provider/model identity, active state, and the effective provider-derived `inputCapacity` when known. |
3877
4043
  | Model catalog | `listModels(query)` | Returns one validated bounded {§model-catalog-wire} page under {§model-catalog}; performs no provider request or selection. |
@@ -3882,10 +4048,10 @@ Core's behavior behind them.
3882
4048
  | §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name? })` | Creates a distinct model-origin root worker with empty history: a fresh conversation over the same world, not a fork or the stable default. |
3883
4049
  | Workspace lifecycle | `forkWorker({ workspaceId, workerId, name? })` | Creates a child worker that branches the source worker's history while sharing workspace state. |
3884
4050
  | §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
3885
- | §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?)` | Returns nonempty loop-seed prompts from the workspace's model-origin root conversations, newest-first. The positive limit defaults to 100; spawned and forked child prompts are excluded. |
4051
+ | §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?)` | Returns nonempty loop-seed prompts from the workspace's model-origin root conversations, newest-first. An omitted limit is `PLURNK_SERVICE_PROMPTS_PAGE`; spawned and forked child prompts are excluded. |
3886
4052
  | Workspace metadata | `listWorkspaces()`, `workspaceDerivationStatus(...)` | Reads current workspace identity and derivation progress. |
3887
4053
  | §methods-worker-read Worker topology | `readWorker({ workspaceId, identity })` | Ownership-bounds an exact id-or-name lookup and returns one durable Worker projection or `null` under {§application-worker-observation}. Supplying both identities or neither is invalid. |
3888
- | §methods-worker-list Worker topology | `listWorkers(workspaceId, query?)` | Returns the workspace's durable Worker projections under {§application-worker-observation}. The origin filter is exact; an explicitly present `parentWorkerId` filters roots (`null`) or one immediate parent (id), while omission returns every lineage position. Each projection carries `kind` (`conversation`, `fork` for a child with a fork boundary, `work` for any other child) and `lifecycle`, the latest work loop's status through {§loop-lifecycle-vocabulary} (`idle` with no work loop), so a directory row shows the same lifecycle glyph the bound worker's own status gauge shows; clients infer neither (#523). |
4054
+ | §methods-worker-list Worker topology | `listWorkers(workspaceId, query?)` | Returns the workspace's durable Worker projections under {§application-worker-observation}. The origin filter is exact; an explicitly present `parentWorkerId` filters roots (`null`) or one immediate parent (id), while omission returns every lineage position. Each projection carries `kind` (`conversation`, `fork` for a child with a fork boundary, `work` for any other child) and `lifecycle`, the representative work loop's status through {§loop-lifecycle-vocabulary} (`idle` with no work loop), so a directory row shows the same lifecycle glyph the bound worker's own status gauge shows; clients infer neither (#523). |
3889
4055
  | §methods-worker-loops Loop lifecycle | `listWorkerLoops({ workspaceId, workerId })` | Ownership-checks the Worker and returns its Loops in sequence order under {§application-loop-observation}, including the validated exact terminal result when one exists. It performs no scheduling or event replay. |
3890
4056
  | Extension actions | `listModuleActions()`, `invokeModuleAction(name, params, context)` | Lists setup-registered `{ name, scope, inputSchema, outputSchema }` descriptors in sorted order. Invocation requires a context matching the registered scope; missing names, forged scope, and missing workspace identity fail before the owner runs. Handler values remain opaque to core. |
3891
4057
 
@@ -3898,26 +4064,26 @@ already durable on the loop remains authoritative:
3898
4064
  |-----------------------|------------------------------------------------------|--------------------------------|--------------------------------------|
3899
4065
  | Provider/model | The resolved request selection must still agree. | Fold. | 409 provider conflict. |
3900
4066
  | `maxTurns` | Keep the durable ceiling. | Fold. | 409 turn-ceiling conflict. |
3901
- | Partial `policy` | Keep the complete durable loop policy. | Fold. | 409 policy conflict. |
4067
+ | `policy` request | Keep the complete durable loop policy. | Fold. | 409 policy conflict. |
3902
4068
 
3903
4069
  The conflict names both selections and directs the caller to cancel or conclude
3904
4070
  the loop before changing configuration. A newly enqueued loop instead persists
3905
4071
  the requested configuration normally.
3906
4072
 
3907
4073
  §methods-loop-run-open-paths **Workspace paths are core-owned context reads.**
3908
- `openPaths` belongs to the prompt frame submitted by the client. The client
4074
+ `openPaths` belongs to the message submitted by the client. The client
3909
4075
  sends paths, never duplicated file bytes; core dispatches one ordinary
3910
4076
  `plurnk`-origin READ per path from inside the owning workspace, and successes
3911
4077
  and failures surface through the normal operation-result contract.
3912
4078
 
3913
- | `runLoop` disposition | Prompt-frame and path behavior |
3914
- |-----------------------|---------------------------------------------------------------------------------------------------|
3915
- | New loop | Persist with the initial frame; publish the frame and READ its paths on turn 1. |
3916
- | Active loop | Persist with the injected frame; publish the frame and READ its paths together on the next turn. |
3917
- | Parked loop | Persist with the waking frame; publish the frame and READ its paths together on the resumed turn. |
4079
+ | `runLoop` disposition | Message and path behavior |
4080
+ |-----------------------|------------------------------------------------------------------------------------------------------|
4081
+ | New loop | Persist with the initial message; publish it and READ its paths on turn 1. |
4082
+ | Active loop | Persist with the injected message; publish it and READ its paths together on the next turn. |
4083
+ | Parked loop | Persist with the waking message; publish it and READ its paths together on the resumed turn. |
3918
4084
 
3919
- If an undelivered frame is promoted into subsequent work under
3920
- {§prompt-loop-containment}, its selected paths travel with it.
4085
+ If an unpublished message is promoted into subsequent work under
4086
+ {§message-loop-containment}, its selected paths travel with it.
3921
4087
 
3922
4088
  §methods-rebind **Binding belongs to the client-interface module.** Core's
3923
4089
  workspace lifecycle calls return exactly the workspace and selected client actor
@@ -3945,7 +4111,7 @@ mutation of its source; a resource-backed execution demands its runtime plus sou
3945
4111
  observation. Unknown schemes, runtimes,
3946
4112
  and tools continue to their ordinary resolver so capability policy cannot turn
3947
4113
  absence into a misleading restriction. The same resolver shapes generated
3948
- scheme references, worker tool documents, and Turn0 surveys. TASK inventory, log KILL,
4114
+ scheme references, worker tool documents, and Turn0 surveys. NOTE, lifecycle declarations, log KILL,
3949
4115
  and label or targetless SEND are log/program control rather than routed
3950
4116
  external demands and therefore remain outside capability selectors.
3951
4117
  Runtime mutations of owned generated entries ({§worker-generated-subtree})
@@ -4105,9 +4271,8 @@ beside database ids, so a client can render and resolve the logical `L/T/S`
4105
4271
  coordinate without fetching all rows and matching locally.
4106
4272
 
4107
4273
  §methods-log-entry-wire **Log entry wire fidelity.** `readLog` and `log/entry`
4108
- preserve causal `source` and parse the row's JSON `attrs` into structured data;
4109
- they also project the row's complete sorted `tags` classification. Client
4110
- interfaces do not reconstruct these fields from operation or origin.
4274
+ preserve causal `source` and parse the row's JSON `attrs` into structured data.
4275
+ Client interfaces do not reconstruct these fields from operation or origin.
4111
4276
 
4112
4277
  §methods-readable-reasoning **Readable provider reasoning remains derived
4113
4278
  provider evidence.** On model SEND and disposition rows, `readLog` and `log/entry`
@@ -4122,8 +4287,8 @@ hands the AST to core's `look`; core owns the full resolver and the no-log
4122
4287
  invariant. The internal closed, rowless observation segment supplies an honest
4123
4288
  numeric loop coordinate for relative `log:///` addressing without leaving
4124
4289
  active lifecycle behind. The segment belongs to the acting worker (`workerId`);
4125
- the READ resolves as `perspectiveWorkerId` when one is given — `log:///`, `reasoning:///`,
4126
- and `ops:///` as that worker sees them — so a client can look at a conversation without
4290
+ the READ resolves `log:///` as `perspectiveWorkerId` when one is given; explicit source
4291
+ authorities retain their identity under {§turn-source-resources}. A client can look at a conversation without
4127
4292
  adding a loop to it. LOOK text anchors resolve through the same
4128
4293
  {§line-anchors} path as READ.
4129
4294
 
@@ -4175,13 +4340,6 @@ defining the public client lifecycle. Multiple client actors have distinct worke
4175
4340
  only the model worker's private log; client action rows are structurally absent
4176
4341
  without an origin filter ({§actor-boundary-isolation}).
4177
4342
 
4178
- ### §versioning Versioning
4179
-
4180
- The typed module seam is released with the service package. Core exposes no
4181
- runtime version or update-advertising action. External protocol compatibility
4182
- and any protocol-level version negotiation belong to the client-interface
4183
- module that publishes that protocol.
4184
-
4185
4343
  ---
4186
4344
 
4187
4345
  ## §packet-assembly Packet assembly
@@ -4214,7 +4372,7 @@ Conditional absence never reorders the surviving default sections.
4214
4372
  | 8 | user | `notices` | Per-turn observations; empty content is omitted. |
4215
4373
  | 9 | user | `git` | Per-turn workspace status; empty content is omitted. |
4216
4374
  | 10 | user | `budget` | `Context Curation`; omitted when capacity is unknown. |
4217
- | 11 | user | `prompt` | Current prompt-entry pointers. |
4375
+ | 11 | user | `messages` | `Open Messages`: immutable message addresses and causal sources ({§message-arrival}). |
4218
4376
  | 12 | user | `recap` | Optional authored operational recap. |
4219
4377
 
4220
4378
  The order favors prefix-cache locality where semantics permit: the definition
@@ -4238,7 +4396,7 @@ sections. It receives no separate engine, database, actor, or request context.
4238
4396
 
4239
4397
  This is strictly a trusted in-process seam, admitted through the common plugin
4240
4398
  trust gate; an external client action cannot invoke it. Whole-list transformation is
4241
- the fork-avoidance valve for alternate packet shapes ({§ecosystem}), while
4399
+ the fork-avoidance valve for alternate packet shapes, while
4242
4400
  overflow recovery and packet projection remain closed engine concerns.
4243
4401
 
4244
4402
  ### §tokenomics Tokenomics: four facts, one curation ruler
@@ -4274,9 +4432,9 @@ time of measurement.
4274
4432
  - **Derivation is exhaustive and demand-led.** Explicit searchable-resource changes may start one coalesced warm. Passive creation and attachment do not. The first model turn starts or joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or full-text coverage. Progress notices make the wait visible. {§derivation-exhaustive}
4275
4433
  - §membership-binary-sniff **Binary truth beats a text label.** Filesystem source acquisition, including tracked members and installed skill resources, inspects up to the first 8192 bytes when extension detection does not identify a binary type. NUL marks `application/octet-stream`; existing binary types retain their declared type. Member projections follow {§membership-source-projection}; installed skill projections follow {§skills-resources}.
4276
4434
  - §tokenomics-agnostic-ruler **One model-agnostic curation ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. `contentWeight = ceil(chars/2)` therefore gives one content one stable number without per-model workspace state or recount passes. It controls curation only; every provider call independently measures the complete request as well as it can.
4277
- - §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Curation` section is one JSON object carrying `logTokensTotal` and `logTokensMax` (and `tokensResponseMax` when an output floor is disclosed), so the block opens as a JSON payload like ```` ```TASK ````. It never presents their difference as free response tokens. The protocol definition directly requires KILL of irrelevant log items and ranges to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe visible cost and curation savings. Generic packet composition and physical-token speculation are absent.
4278
- - §tokenomics-pressure-inventory **Pressure identifies its reclaimable concentration.** At 80% of `logTokensMax`, a Markdown `> [!WARNING]` block follows the JSON with `> YOU MUST KILL superseded, stale, or irrelevant log items and ranges.` New output withholding replaces that mandate under {§context-output-warning}. The JSON may include `logTokensLargest`: at most five retained log items, each `{path, logTokens}`, ranked by that charge descending and then path. Native-only, suppressed, and metadata-only items remain eligible: whole-item KILL can reclaim their actual contribution. Include the largest prefix that fits; drop the optional list before the warning. Both participate in the final fixed-point total and complete request admission check.
4279
- - §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as stable content identity. `weight` is stored beside that content and is never keyed or recomputed by model.
4435
+ - §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Curation` section is one JSON object carrying `logTokensTotal` and `logTokensMax` (and `tokensResponseMax` when an output floor is disclosed). It never presents their difference as free response tokens. The protocol definition directly requires KILL of irrelevant log items and ranges to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe visible cost and curation savings. Generic packet composition and physical-token speculation are absent.
4436
+ - §tokenomics-pressure-inventory **Pressure identifies its reclaimable concentration.** At `PLURNK_SERVICE_BUDGET_PRESSURE` of `logTokensMax`, a Markdown `> [!WARNING]` block follows the JSON with `> YOU MUST KILL superseded, stale, or irrelevant log items and ranges.` New output withholding replaces that mandate under {§context-output-warning}. The JSON may include `logTokensLargest`: at most `PLURNK_SERVICE_BUDGET_LARGEST_ITEMS` retained log items, each `{path, logTokens}`, ranked by that charge descending and then path. Native-only, suppressed, and metadata-only items remain eligible: whole-item KILL can reclaim their actual contribution. Include the largest prefix that fits; drop the optional list before the warning. Both participate in the final fixed-point total and complete request admission check.
4437
+ - §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** A settled channel's `content_hash` (SHA-256) is its body's identity in the content store ({§content-store}); a writer may bind it, a bound hash must match the content, and an active stream has none until it settles. `weight` is stored beside that content and is never keyed or recomputed by model.
4280
4438
  - §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity beneath the normalized {§inference-ledger} and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` sums every USD-expressible request and is `null` only when no request is expressible; a response-less failure or an uncataloged model is skipped, never allowed to erase the expressible evidence. Each derived aggregate usage field independently sums its reported quantity, so heterogeneous detail coverage remains partial rather than becoming fictitiously complete. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot KILL, so they never alter the model-facing Budget ledger.
4281
4439
  - §tokenomics-negative-pressure **Negative curation pressure is honest but never submitted.** The provisional readout may report `logTokensTotal` above `logTokensMax`. Crossing the maximum withholds new returned output under {§context-output-admission}; no over-ceiling packet reaches `provider.generate`. Output admission creates neither a strike nor another turn.
4282
4440
 
@@ -4284,7 +4442,7 @@ time of measurement.
4284
4442
 
4285
4443
  Operations and their results are execution history. Packet admission controls
4286
4444
  only whether newly presented returned output fits, never what executed or what
4287
- the model's TASK inventory means.
4445
+ the model's lifecycle declaration means.
4288
4446
 
4289
4447
  ```mermaid
4290
4448
  flowchart TD
@@ -4302,7 +4460,7 @@ flowchart TD
4302
4460
  prompt -->|no| stop
4303
4461
  ```
4304
4462
 
4305
- §context-output-selection **First presentation, not a turn-number heuristic, owns admission.** Canonical log-body resolution distinguishes authored input from returned output. Before provider I/O, the run boundary records the first admission turn of each newly visible returned body. On measured overflow, that batch's returned bodies and native parts are withheld together. Already-admitted output, authored TASK/program/message bodies, actual statuses and Problems, effects, child state, and immutable evidence remain unchanged. Bodyless and initially suppressed rows require no admission. Packet assembly is pure. No recovery turn, generated TASK, KILL operation, strike, or extra model attempt is manufactured.
4463
+ §context-output-selection **First presentation, not a turn-number heuristic, owns admission.** Canonical log-body resolution distinguishes authored input from returned output. Before provider I/O, the run boundary records the first admission turn of each newly visible returned body. On measured overflow, that batch's returned bodies and native parts are withheld together. Already-admitted output, authored NOTE/lifecycle/program/message bodies, actual statuses and Problems, effects, child state, and immutable evidence remain unchanged. Bodyless and initially suppressed rows require no admission. Packet assembly is pure. No recovery turn, generated lifecycle declaration, KILL operation, strike, or extra model attempt is manufactured.
4306
4464
 
4307
4465
  | Projection fact | Meaning |
4308
4466
  |---|---|
@@ -4314,11 +4472,25 @@ flowchart TD
4314
4472
 
4315
4473
  §context-output-warning **New omission escalates the one curation warning.** The admitting request renders `> [!WARNING]` followed by `> YOU MUST ONLY KILL superseded, stale, or irrelevant log content in bulk.` beneath its JSON readout, replacing the ordinary pressure mandate even when withholding brings usage below 80%. Historical omission alone does not retrigger it. The warning participates in exact packet measurement; optional largest-items entries yield space first.
4316
4474
 
4317
- §context-output-hard-413 **Unfittable retained context fails honestly.** If the request still exceeds the ceiling after withholding newly presented output, it terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem without provider I/O. No unrelated older history or authored inventory is pruned. Separately, provider capacity failures follow {§provider-surface-capacity}: withholding automatic prompt-body projection permits a retry only when it changes the request; otherwise the exact provider-owned 413 terminates the request-only model turn.
4475
+ §context-output-hard-413 **Unfittable retained context fails honestly.** If the request still exceeds the ceiling after withholding newly presented output, it terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem without provider I/O. No unrelated older history or authored memory is pruned. Separately, provider capacity failures follow {§provider-surface-capacity}: withholding automatic prompt-body projection permits a retry only when it changes the request; otherwise the exact provider-owned 413 terminates the request-only model turn.
4318
4476
 
4319
4477
  - §tokenomics-fetch-fits-free **Withholding is not deletion.** The complete result lands once. READ/FIND of its original log address retain the readable body and original coordinates; scoped READ creates a fresh output occurrence subject to the same admission rule. Source resources and forensic evidence remain unchanged. Deliberate scoped KILL, unlike withholding, removes lines from subsequent readable projections ({§log-readable-projection}).
4320
4478
 
4321
- - §loop-terminals **Engine-imposed terminals are HTTP-precise** — the loop-status vocabulary, one meaning each: `200` concluded (terminal inventory with at least one completed task) · `499` model-abandoned (a nonempty all-failed inventory, or a cancel) · `429` maxTurns exhausted · `413` token-ceiling recovery failure or provider input-capacity failure after changed-request recovery · `500` strike threshold or invalid-emission exhaustion (distinct Problem types; `508` when the crossing strike was a detected cycle) · `504` loop timeout / exec-timeout restamp · `202` waiting — a TASK inventory waiting on a live obligation or explicit deadline/poll ({§wait-obligation-matrix}, {§worker-wait-timing}); an empty untimed wait continues at `102`, never implicit success · `100`/`102` queued/running. Never a catch-all, never a new value without changing the owning schema.
4479
+ - §loop-terminals **Lifecycle outcomes are HTTP-precise.**
4480
+
4481
+ | Status | Outcome |
4482
+ |---|---|
4483
+ | 100 / 102 | Queued / running |
4484
+ | 202 | WAIT or answered work joining a live obligation ({§wait-obligation-matrix}, {§worker-wait-timing}) |
4485
+ | 200 | Messages answered, results observed, held work settled |
4486
+ | 499 | Worker-scope or client cancellation |
4487
+ | 429 | Turn allowance exhausted |
4488
+ | 413 | Token-ceiling recovery failure or provider input-capacity failure after changed-request recovery |
4489
+ | 500 / 508 | Strike threshold or invalid-emission exhaustion / crossing strike caused by a cycle |
4490
+ | 504 | Loop timeout or exec-timeout restamp |
4491
+
4492
+ An empty WAIT continues at 102. The exact terminal result retains its Problem;
4493
+ status classes are not catch-all replacements for that evidence.
4322
4494
 
4323
4495
  ### §env-delta The environment delta: what changed since the model last looked
4324
4496
 
@@ -4356,7 +4528,10 @@ pre-existing broadcast history stays out while later occurrences remain
4356
4528
  deliverable even before its first packet. A fork instead copies the parent's
4357
4529
  cursor and captures its own fork high-water atomically with worker creation
4358
4530
  ({§machine-processes-fork-pending-activity}). Observer rows retain the source
4359
- identity and never publish another occurrence.
4531
+ identity and never publish another occurrence. Newly materialized ambient and
4532
+ terminal-stream rows emit the ordinary client notification
4533
+ ({§notifications-log-entry-notify}) before the next inference; an idempotent
4534
+ pull does not emit an existing row again.
4360
4535
 
4361
4536
  §env-delta-worker-entry-visibility **The commons is global; every other
4362
4537
  resource follows lineage.** A successful state-changing `EDIT`, `COPY`, `MOVE`,
@@ -4368,8 +4543,8 @@ ordinary operation evidence still reaches that child's direct parent.
4368
4543
 
4369
4544
  | Producer / event | Durable occurrence | Observer projection |
4370
4545
  | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
4371
- | §env-delta-child-activity Direct-child activity | Every final op-bearing child log row except the runtime's own rows — `_plurnk` initialization, maintenance, and operation turns are private to the child: prompt, continuation inventory, operation result, or actionless error. | Direct parent only; one exact attributed row born body-suppressed. Provider reasoning, calls, rejected emissions, turnOps, and harness maintenance do not cross. |
4372
- | §env-delta-child-termination Direct-child termination | The child's exact terminal loop result, except loops containing only `_plurnk` operation or maintenance turns. A conclusion before the first turn still reports, including failed spawns. The observation is untargeted, a SEND message representing the child's disposition: `source` (`worker://<name>`) names the actor and the READ address of its deliverable, and no commons-shaped `worker:///<name>` target is invented (#567). | Direct parent only; a 2xx deliverable is born visible and every failure is body-suppressed ({§worker-scheme-collect}). Excluded administrative loops create no pending child-result edge. |
4546
+ | §env-delta-child-activity Direct-child activity | Child-authored final EDIT, COPY, MOVE, SEND, executor invocation, WORK, FORK, and non-log KILL receipts, including failures. `_plurnk` initialization, maintenance, and operation turns stay with the worker. A reply already delivered to the parent uses its reply occurrence instead ({§message-reply-delivery}). | Direct parent only; one exact attributed row born body-suppressed. Incoming message projections ({§message-arrival}), NOTE, READ (including executor-output READs), FIND, BARE, WAIT, and log KILL never create activity occurrences. Provider reasoning, calls, rejected emissions, and turn sources do not cross automatically. |
4547
+ | §env-delta-child-termination Direct-child termination | The child's exact terminal loop result, except loops containing only `_plurnk` operation or maintenance turns. A conclusion before the first turn still reports, including failed spawns. `source` names the actor; the READ target selects its exact loop result ({§worker-loop-result}). | Direct parent only; an ordinary bounded READ projection of the retained occurrence, never a fresh lookup of the child's latest loop. The outcome's own body is visible within the ordinary READ bound; replies are separate messages and are never copied or deduplicated by content ({§worker-scheme-collect}). Excluded administrative loops create no pending child-result edge. |
4373
4548
  | §env-delta-commons-mutation Commons mutation | One successful resolved operation whose landed effects touch `worker:///...`. | Every existing worker; one body-suppressed row per observer, deduplicated with any lineage audience. |
4374
4549
  | §env-delta-filesystem-narration Project-file divergence | Runtime-owned reconciliation evidence remains in the runtime actor's own log. | No ambient observer row. Current content remains addressable and stale hash edits reject at their owned boundary. |
4375
4550
  | §env-delta-entry-materialization Executor `entry()` sink | The runtime records typed materialization evidence under its owning actor. | No ambient observer row unless the resulting operation itself is direct-child activity or a commons mutation ({§exec-entry-sink}). |
@@ -4380,19 +4555,19 @@ ordinary operation evidence still reaches that child's direct parent.
4380
4555
  | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
4381
4556
  | `worker_id` | The worker whose self-contained log owns the materialized row. |
4382
4557
  | `origin` | The actor tier that wrote the row; a materialized delta is `_plurnk`. |
4383
- | `source` | The immediate causal identity in this log: a lineage or commons observation uses canonical `worker://<producer>`, a terminal stream observation uses its causal `log:///<coord>/<runtime>`, and a subsystem observation may use its stable token (for example `file`). Self-authored rows omit it. |
4558
+ | `source` | The attributed actor or subsystem: a lineage or commons observation uses canonical `worker://<producer>`; a subsystem observation may use its stable token (for example `file`). Self-authored rows omit it. Stream invocation correlation belongs to the subscription/publication relationship, not this field. |
4384
4559
 
4385
- §env-delta-no-coalescing **Activity is never coalesced.** Each admitted child
4386
- operation and each commons mutation has one occurrence identity. Combining
4560
+ §env-delta-no-coalescing **Activity is never coalesced.** Each eligible child
4561
+ action and each commons mutation has one occurrence identity. Combining
4387
4562
  them would destroy causal order and conflate event replay with a state
4388
4563
  comparison.
4389
4564
 
4390
- §env-delta-passive **Observation never forces a turn.** Deltas materialize only
4565
+ §env-delta-passive **Passive observation never forces a turn.** Deltas materialize only
4391
4566
  while a packet is already assembling. Intermediate child activity and commons
4392
4567
  broadcasts therefore cannot wake an idle worker. Urgent directed communication
4393
- uses the voice door ({§actor-boundary-two-doors}); direct-child terminal
4394
- disposition alone carries the structured-concurrency wake owned by
4395
- {§worker-scheme-collect}. Stream progress remains owned by {§exec-stream}.
4568
+ uses the voice door ({§actor-boundary-two-doors}); child conclusions and addressed
4569
+ replies use {§worker-lifecycle-child-wake} and {§message-reply-delivery}.
4570
+ Stream progress remains owned by {§exec-stream}.
4396
4571
 
4397
4572
  ---
4398
4573
 
@@ -4423,12 +4598,12 @@ their boundaries ({§log-wire-format}).
4423
4598
  | `inject` | system | Authored Markdown | {§packet-inject} |
4424
4599
  | `log` | user | Markdown H3 records with JSON metadata | {§log-wire-format} |
4425
4600
  | `worker` | user | JSON `path` with the literal Worker address, `parent` (address or `null`), `loop`, `turn` | {§packet-current-turn} |
4426
- | `delegation` | user | JSON `{workers, streams}` status/path pointers, each `[]` when empty | {§child-orientation} |
4601
+ | `delegation` | user | JSON `{workers, streams}` | {§child-orientation} |
4427
4602
  | `errors` | user | JSON status/log-path pointers | {§operation-results} |
4428
4603
  | `notices` | user | Terse observation bullets | {§notice-drain-on-read} |
4429
4604
  | `git` | user | Working-tree state in a NOTE blockquote | {§packet-cache-monotone} |
4430
4605
  | `budget` | user | JSON curation usage and ceiling; pressure guidance when needed | {§tokenomics-neutral-telemetry} |
4431
- | `prompt` | user | JSON `prompt://<worker>/<loop>/<N>` pointers | {§prompt-entry} |
4606
+ | `messages` | user | JSON pointers to the loop's unanswered immutable messages, path and source | {§message-arrival} |
4432
4607
  | `recap` | user | Optional authored operational recap | {§recap} |
4433
4608
 
4434
4609
  §packet-stored-shape **A model packet preserves the rendered request and, only
@@ -4540,38 +4715,87 @@ reasoning continuation. Readable reasoning remains independent.
4540
4715
  | row producer | ordinary visible projection |
4541
4716
  |---|---|
4542
4717
  | any `READ` or `FIND` | complete selected operation result |
4543
- | `TASK` | complete canonical Plurnk Plan JSON {§plan-value} |
4544
- | actionless lowercase `prompt` | budgeted head under {§prompt-projection} |
4718
+ | `NOTE`, `WAIT` | complete literal authored text |
4719
+ | inbound `SEND` from outside the workspace | budgeted head under {§message-projection} |
4545
4720
  | structured `EDIT` receipt or textual `COPY`/`MOVE` effects | complete receipt-owned join context |
4546
4721
  | every other nonempty body | head bounded independently by `PLURNK_SERVICE_PREVIEW_LINES` and `PLURNK_SERVICE_PREVIEW_CHARS` |
4547
4722
  | bodyless row | metadata only; no coordinate lines; `logTokens` includes any selected native part |
4548
4723
 
4724
+ §markerless-first-page **Every markerless retrieval takes the same implicit marker.** A marker's
4725
+ unit is whatever its projection counts, so `PLURNK_SERVICE_PREVIEW_LINES` is the first page of
4726
+ all of them: lines of text, bytes of a byte view ({§read-bytes}), positions of a FIND. It is one
4727
+ choice with one home; no operation carries a page size of its own.
4728
+
4549
4729
  Markerless text READs select their page with the same line/character bound as
4550
4730
  ordinary previews, before result storage and packet rendering. Explicit scopes
4551
4731
  remain exact. Automatic stream delivery uses that markerless selector too;
4552
4732
  its range or region describes the selected content and the complete stream
4553
4733
  remains addressable. This selection is not a second rendering-time cut.
4554
4734
 
4555
- READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. TASK inventory is likewise complete while visible: the model's task inventory is serialized once as compact JSON, never preview-clipped. Reasoning arrives through ordinary scoped READs ({§reasoning-history}). Prompt rows follow their separate adaptive projection contract. Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again. Rejected-emission artifacts, SEND/WORK/FORK bodies, execution commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. When a visible projection differs from its canonical body, metadata carries `chunk` with the exact selected and complete extents defined by {§log-wire-format}; complete and fully suppressed bodies omit it. ```` ```READ (log:///<coordinate>/<OP>) ```` selects untrimmed lines in original coordinates under {§log-readable-projection}; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. ```` ```FIND (log:///...) ```` and search match that same readable view. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
4556
-
4557
- §prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt://<worker>/<loop>/<id>` as an explicitly addressed text/markdown entry — written before any turn of its loop executes — then published to its first model turn as one actionless lowercase `prompt` log row; that row, not the entry, records publication. No synthetic EDIT or READ operation is invented. The row is born visible and obeys {§body-projection}. The **Active Prompts** section closes the user-slot status clump as a paths-only list (`* prompt://<worker>/<loop>/<id>`), so every frame remains directly READable after its log row's body is suppressed or its active projection is retired.
4558
-
4559
- §prompt-causal-source **Prompt authorship and delivery are distinct facts.** The harness publishes every prompt row with `origin="_plurnk"`; the row's existing `source` carries the canonical address of a different causal actor. Native WORK, FORK, and directed worker SEND derive `worker://<sender>` from the authenticated sender worker ID. A trusted exterior adapter may supply its own canonical actor address through {§methods-loop-run}. An absent source means the owning worker itself. Attribution persists with the prompt frame through active delivery, parking, orphan recovery, restart, and later log projection; model syntax cannot author it.
4560
-
4561
- §prompt-projection **Prompt storage is unbounded by model context; automatic materialization is not.** Core persists every accepted prompt completely before packet assembly. The selected provider's derived `inputCapacity` and the alias-resolved percentage from `PLURNK_SERVICE_PROMPT_PROJECTION` derive one aggregate curation-weight allowance for visible prompt bodies. Complete prompt bodies render when their aggregate weight fits. Otherwise all visible prompt rows share the allowance: full bodies consume only their required share, unused shares are redistributed, and partial bodies render the largest leading complete-line region that fits their share or an exact character-bound prefix when the first physical line alone is larger. The sum of their rendered body weights never exceeds the allowance. Every partial body carries its exact `chunk` metadata. The canonical `prompt://<worker>/` entry remains complete and READ/FIND-addressable; its `log:///` body additionally obeys deliberate curation under {§log-readable-projection}. When provider input capacity is unknown the percentage is underivable, so prompt rows retain the ordinary bounded projection rather than inventing capacity. This policy never rejects, summarizes, or discards a prompt because it exceeds a context window.
4735
+ READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. NOTE and lifecycle bodies are complete literal text while visible, never preview-clipped. Reasoning arrives through ordinary scoped READs ({§reasoning-history}). Arrivals from outside the workspace follow their separate adaptive projection contract ({§message-projection}). Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again. Rejected-emission artifacts, SEND/WORK/FORK bodies, execution commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. When a visible projection differs from its canonical body, metadata carries `preview` under {§packet-extent-metadata}; complete and fully suppressed bodies omit it. ```` ```READ (log:///<coordinate>/<OP>) ```` selects untrimmed lines in original coordinates under {§log-readable-projection}; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. ```` ```FIND (log:///...) ```` and search match that same readable view. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
4562
4736
 
4563
- §prompt-address The frame uses its literal Worker name: `prompt://alice/<loop>/<id>`, where `id` is an opaque eight-character hexadecimal identifier. Any workspace actor can read or search it. Identity is not arrival order or a turn number. The entry separately persists its delivery `ordinal`; the initial prompt reserves ordinal 1 before materialization. Repeated initialization reuses that prompt's existing identity. Prompt publication follows the producing Worker's loop, independently of who reads the source.
4737
+ §message-arrival **A message source, its log observations and its reply state are distinct.**
4564
4738
 
4565
- §prompt-loop-containment A loop contains every prompt that arrives before it
4566
- concludes; the next turn publishes every entry for which
4567
- that loop has no `op='prompt'` row, oldest first. Every still-undelivered frame
4568
- at conclusion moves into one source-keyed recovery loop with its opaque ID intact and a new delivery ordinal; that loop's
4569
- first turn publishes the complete ordered set exactly once. Recovery retries
4570
- complete the same queued loop and never mint duplicate work. Output withholding
4571
- preserves readable prompt rows; explicit KILL follows the ordinary log
4572
- contract.
4573
-
4574
- §completion-defers-to-prompts **A completion never answers a conversation the model has not seen.** A model TASK that would end the loop at `200` while the loop still contains an unpublished prompt frame ({§prompt-loop-containment}) is deferred at `102` with a receipt naming the arrival; the next turn boundary publishes the frame as usual and the model completes after it. The arrival is not the model's doing, so the deferral is neither a refusal nor a strike. `499` is not deferred: declaring failure is weighing it, and the orphan recovery loop still carries any unpublished frame. The recovery loop also remains the guard for the one true race, a frame written after the terminal decision is committed.
4739
+ | Fact | Owner | Curation effect |
4740
+ |---|---|---|
4741
+ | Accepted body, attachments, address and causal source | Durable inbox message | None; ordinary READ/FIND/COPY can recover the source. |
4742
+ | Arrival seen at a turn boundary | One inbound SEND log row, `origin="_plurnk"`, `attrs.kind="message"` | Ordinary KILL can trim or remove this observation. |
4743
+ | Answered messages | Successful executed reply, {§send-response-receipt} | None; curation cannot retract delivery. |
4744
+
4745
+ Every accepted message enters its recipient loop's inbox in arrival order, with its selected
4746
+ paths, and publishes exactly once at the next turn boundary. **Open Messages** lists the
4747
+ unanswered messages by their immutable source address (`path`) and optional causal `source`,
4748
+ not a log coordinate. Each arrival receipt's `resource` names that same retained source.
4749
+ Trusted protocol modules supply message addresses in their own scheme;
4750
+ native arrivals use `message://<recipient>/<opaque-id>`, separate from the worker's
4751
+ actor and scratch addresses. Ordinary worker scratch remains writable. Source bodies
4752
+ are not edited or deleted through resource operations; independently curatable READs and
4753
+ arrival rows obey {§log-readable-projection}. No curation operation answers a message.
4754
+ Within a workspace an address identifies exactly one accepted message. Reusing it for
4755
+ another admission is a 409 conflict, not a second message or an implicit content update.
4756
+
4757
+ §message-reply-delivery **A reply is delivered once, not re-enqueued as a request.**
4758
+
4759
+ | Audience | Delivery | Effect |
4760
+ |---|---|---|
4761
+ | Assigned worker | Its conversation, even when another actor answered | Visible reply; wakes eligible parked work without a new Open Message or loop. |
4762
+ | Original native sender | That worker, if distinct from the assigned worker | The same reply, through the same wake and observation path. |
4763
+ | Exterior sender | The assigned conversation's protocol adapter | The adapter delivers the answer through its standard message channel. |
4764
+ | Replying actor | Its own executed SEND | No duplicate ambient occurrence. |
4765
+
4766
+ The successful SEND and its addressed occurrences commit together. Reply occurrences use
4767
+ the ordinary durable ambient cursor and wake revision; curation cannot revoke delivery or
4768
+ replay it. An addressed reply replaces the same parent's generic activity observation.
4769
+ Child completion is a separate READ of its execution outcome; replies are not outcome bodies.
4770
+ The complete outcome remains available at its {§worker-loop-result} address.
4771
+ Unobserved replies prevent conclusion just as unobserved child results do. All operation
4772
+ producers notify the same settlement path after durable execution; reply wake-up shares
4773
+ {§worker-optimistic-settlement}, without delaying the replying program.
4774
+
4775
+ §message-short-identity **The model addresses a message by its short name.** Every message carries
4776
+ `message://<worker>/<key>` (`key_path`), the form the worker docs teach, and that is what the packet
4777
+ shows in Open Messages and in an arrival row's `resource`. A client's own identity for the same
4778
+ message — an AG-UI message UUID, an A2A address — stays the durable `path` that correlation,
4779
+ delivery and reply accounting use, and remains addressable in its own scheme; the short form is an
4780
+ additional alias. Answering either reaches the same message. Origin (operator, 2026-09-18): the
4781
+ packet showed a 77-character `agui://anonymous/threads/…/messages/<uuid>` twice per open message,
4782
+ while the docs taught the short form.
4783
+
4784
+ §message-causal-source **Message authorship and delivery are distinct facts.** The harness publishes every arrival row; the row's `source` carries the canonical address of the causal actor. Native WORK, FORK, and directed worker SEND derive `worker://<sender>` from the authenticated sender worker ID. A trusted exterior adapter supplies its own canonical actor address through {§methods-loop-run}: the AG-UI bridge names the client's message under `agui://` ({§agui-run-source}), the inbound A2A adapter under `a2a://`. An absent source means the owning worker itself. Attribution persists with the message through the inbox, parking, orphan recovery, restart, and later log projection; model syntax cannot author it. The wire renders the row's `source` and omits its `origin`, which is constant for every arrival; the Open Messages pointer carries the same source ({§message-arrival}) — except where the source is the transport that minted this very message, which says nothing the address does not ({§message-short-identity}).
4785
+
4786
+ §message-projection **Message storage is unbounded by model context; automatic materialization is not.** Core persists every accepted message completely before packet assembly. The selected provider's derived `inputCapacity` and the alias-resolved percentage from `PLURNK_SERVICE_PROMPT_PROJECTION` derive one aggregate curation-weight allowance for the visible bodies of arrivals other than a peer worker's — every `source` that is not a `worker://` address, the loop's own assignment included. Complete bodies render when their aggregate weight fits. Otherwise all such visible rows share the allowance: full bodies consume only their required share, unused shares are redistributed, and partial bodies render the largest leading complete-line region that fits their share or an exact character-bound prefix when the first physical line alone is larger. The sum of their rendered body weights never exceeds the allowance. Every partial body carries `preview` under {§packet-extent-metadata}. The row remains complete and READable by coordinate; its `log:///` body additionally obeys deliberate curation under {§log-readable-projection}. A peer worker's message takes the ordinary bounds. When provider input capacity is unknown the percentage is underivable, so arrival rows retain the ordinary bounded projection rather than inventing capacity. This policy never rejects, summarizes, or discards a message because it exceeds a context window.
4787
+
4788
+ §message-loop-containment A loop contains every message that arrives before it
4789
+ concludes; the next turn boundary publishes every inbox row the loop has not yet
4790
+ published, oldest first, and stamps each with the row it became. Ordinal 1 is the loop's
4791
+ own assignment and shares the loop's fate: a loop that fails before its first turn does
4792
+ not replay it. Every other still-unpublished message at conclusion moves into one
4793
+ source-keyed recovery loop, renumbered from its first, whose headline it becomes; that loop's first turn publishes the complete
4794
+ ordered set exactly once. Recovery retries complete the same queued loop and never
4795
+ mint duplicate work. Output withholding preserves readable arrival rows; explicit
4796
+ KILL follows the ordinary log contract.
4797
+
4798
+ §completion-defers-to-messages **Conclusion does not cross an unanswered arrival.** The end-of-program check includes messages that arrived during inference. The final database transition rechecks unanswered messages atomically. An arrival that wins the race continues the current loop; one admitted after conclusion belongs to a new loop. Orphan recovery preserves messages accepted before an independently forced termination.
4575
4799
 
4576
4800
  §packet-catalog **Catalogs are query results, not packet state.** The packet
4577
4801
  stores no materialized manifest. Complete and one-level entry directories,
@@ -4601,7 +4825,8 @@ retain distinct contracts and lifetimes.
4601
4825
  an unfittable retained context fails before inference ({§context-output-hard-413}).
4602
4826
  - §log-row-self-explains **Every ≥400 pointer names a record that states its
4603
4827
  why.** A model-operation failure is the model's own operation result; its
4604
- Problem Details `instance` is that row's `log:///` URI and packet wire renders
4828
+ Problem Details `instance` retains the originating occurrence URI; when absent,
4829
+ persistence assigns that row's `log:///` URI. Packet wire renders
4605
4830
  the contracts-owned compact `{§problem-projection}` on its meta line whether
4606
4831
  its body is visible or suppressed. The enclosing row owns status, model-facing path, source, and target;
4607
4832
  an identical extension is not repeated inside the projection. No
@@ -4611,9 +4836,9 @@ retain distinct contracts and lifetimes.
4611
4836
  failure status, a top-level string `error`, or mismatched result/problem
4612
4837
  statuses violate the producer contract and fail hard. Genuine
4613
4838
  engine-internal faults crash and never mint model-facing rows.
4614
- - **Asynchronous work does not weaken the contract.** A stream-producing operation returns its initial `102` after acquisition. At conclusion the subscription stores the exact universal terminal result; `stream/concluded` carries it unchanged; the next ambient terminal READ merges it with the stream payload and assigns the committed `log:///.../READ` Problem instance. Timeouts and service cancellations replace the complete terminal result with a new valid 504/499 Problem—they never mutate a status while retaining a contradictory Problem.
4839
+ - **Asynchronous work does not weaken the contract.** A stream-producing operation returns its initial `102` after acquisition. At conclusion the subscription stores the exact universal terminal result; `stream/concluded` carries it unchanged; the next ambient terminal READ merges it with the stream payload and preserves its Problem instance, assigning the committed `log:///.../READ` URI only when absent. Timeouts and service cancellations replace the complete terminal result with a new valid 504/499 Problem—they never mutate a status while retaining a contradictory Problem.
4615
4840
  - **Self-explaining rows.** A problem `title` names the stable class and `detail` states the occurrence-specific cause. Producer-known operands belong in factual extensions. `stage` appears only when neighboring stages imply different recovery; `recovery` states one generally valid next action; `retryable` is true only when the producer recommends automatically retrying the identical request. Unknown recovery or retryability is omitted rather than guessed. General workflow teaching stays in the packet rather than being duplicated into every failure. The runtime-neutral writing contract is owned by `@plurnk/plurnk-contracts`.
4616
- - **Exact Problems cross durable and external boundaries.** Scheme capabilities, proposal application, subscription conclusion, loop settlement, AG-UI, clients, digests, and benchmark records preserve the originating Problem object. The model packet alone derives `{§problem-projection}` without mutating that object. An adapter may add the durable `instance`; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, a scheduler projection, or a legacy string. A failed boundary without a valid Problem is a contract violation and fails hard.
4841
+ - **Exact Problems cross durable and external boundaries.** Scheme capabilities, proposal application, subscription conclusion, loop settlement, AG-UI, clients, digests, and benchmark records preserve the originating Problem object. The model packet alone derives `{§problem-projection}` without mutating that object. An adapter may add a missing durable `instance`, never replace an existing one; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, a scheduler projection, or a legacy string. A failed boundary without a valid Problem is a contract violation and fails hard.
4617
4842
  - **Caught diagnostics are bounded.** Core-owned Problems may include a bounded preview of a caught runtime diagnostic when it states the occurrence-specific cause. `PLURNK_SERVICE_ERROR_DETAIL_LIMIT` owns that model-facing character bound; complete errors remain in daemon diagnostics. Input validation and stable contract failures do not spend this allowance on implementation text.
4618
4843
  - §notice-drain-on-read **Notices** - the few observations that are not log rows render one terse line under their distinct `## Notices` section, never a JSON dump. Packet rendering normalizes whitespace, bounds the producer message with the shared preview limits, and appends any typed position. The notice buffer drains on read; event Notices appear on at most one packet. Stateful derivation progress and provider availability coalesce in the buffer, so clients observe every checkpoint live while a later model packet receives only the current state under ordinary level filtering.
4619
4844
  - §rail-accounting-private **Rail accounting is private.** Visibility is owned by {§engine-rails}: the model sees concrete failures from admitted turns, never rejected emissions, attempt counts, the strike streak, or cycle detection. Surfacing internal state creates a gamification surface where the model optimizes for engine metrics instead of the task.
@@ -4630,7 +4855,7 @@ retain distinct contracts and lifetimes.
4630
4855
  |---|---|---|
4631
4856
  | `grammar_unenforced` | engine rail verdict, or a forwarded provider transport anomaly such as a discarded-channel escape | content-offset when the observed position maps into content; none for a reasoning-prefix divergence |
4632
4857
  | `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | content-offset into the model's emission |
4633
- | `search_progress` | repository materialization/indexing lifecycle ({§mimetype-surface}); structured phase, count, and percent; `level: info`, `warn` when a completed pass carries failed members ({§derivation-member-failure}), `error` on terminal failure | none |
4858
+ | `search_progress` | repository materialization/indexing lifecycle ({§persistent-search-index}); structured phase, count, and percent; `level: info`, `warn` when a completed pass carries failed members ({§derivation-member-failure}), `error` on terminal failure | none |
4634
4859
  | `git_inspection_refused` | engine membership — automatic Git inspection refused a supplied repository whose config declares a `filter.*` program ({§membership-git-hermetic}); names the key; `level: warn`, once per workspace until the key changes or clears | none |
4635
4860
 
4636
4861
  §notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `grammar_unenforced` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
@@ -4645,7 +4870,8 @@ retain distinct contracts and lifetimes.
4645
4870
  | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
4646
4871
  | Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its package-owned SqlRite statements; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
4647
4872
  | `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
4648
- | `digestDir` | Selects the output directory. `run` removes and recreates it so stale packet artifacts cannot survive; concurrent callers use distinct directories. |
4873
+ | `digestDir` | Selects a nonempty output directory. Both `run` and `requiem` refuse an output containing the input pathname or its resolved database before database/provider I/O or output writes; normalized and real paths participate in that check. `run` removes and recreates output so stale artifacts cannot survive; concurrent callers use distinct directories. |
4874
+ | Reader lifetime | Both methods close their database reader on successful or failed reads, before rendering output or awaiting witness inference. |
4649
4875
  | `workerId` | Narrows workers and every dependent loop, turn, turn-attached logical inference, specialization, physical request, and log row to that one worker. |
4650
4876
  | `workspaceId` | Narrows workers plus every logical inference and dependent evidence owned by one workspace, when both selectors are present they intersect. |
4651
4877
 
@@ -4655,7 +4881,7 @@ retain distinct contracts and lifetimes.
4655
4881
 
4656
4882
  §digest-wire-line **Wire health aggregated.** Each worker summary renders a `Wire:` line — total physical provider requests, error-outcome count, and the error percentage when nonzero. Provider-level failures are absorbed by retries below the packet stream, so without this aggregate a rate-limit storm is invisible in every summary while the model's experience stays clean.
4657
4883
 
4658
- §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log event with its initial and current projection, causal `source`, tags, and structured `attrs`; every exact log-KILL target effect; the exact Problem on every failed row; each loop's exact terminal result; and every ordered physical provider request. Programs still produce chronological `assistant.md` artifacts after every READ receipt is KILLed; source is independent of log curation. Each stored packet validates independently: one malformed historical packet remains exact raw evidence with its complete validation error chain and never prevents healthy turns from being projected. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. A worker's Cost line names how many settled requests carry no usage at all (errored or aborted exchanges) — their server-side spend is unrecorded rather than silently priced as zero. The reasoning chronology distinguishes readable reasoning content from provider-reported reasoning usage: when tokens were reported but no readable content was returned, it states both facts instead of implying that no reasoning occurred. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and durable resource coordinates render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; valid packet files remain byte-identical records of what the model saw.
4884
+ §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log event with its initial and current projection, causal `source`, and structured `attrs`; every exact log-KILL target effect; the exact Problem on every failed row; each loop's exact terminal result, settlement time, scheduled due time, recurring interval, and recurrence lineage; and every ordered physical provider request. Programs still produce chronological `assistant.md` artifacts after every READ receipt is KILLed; source is independent of log curation. Each stored packet validates independently: one malformed historical packet remains exact raw evidence with its complete validation error chain and never prevents healthy turns from being projected. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. A worker's Cost line names how many settled requests carry no usage at all (errored or aborted exchanges) — their server-side spend is unrecorded rather than silently priced as zero. The reasoning chronology distinguishes readable reasoning content from provider-reported reasoning usage: when tokens were reported but no readable content was returned, it states both facts instead of implying that no reasoning occurred. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and durable resource coordinates render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; valid packet files remain byte-identical records of what the model saw.
4659
4885
 
4660
4886
  Unrecognized actionless log rows are retained and labelled as such, not
4661
4887
  interpreted as executable turnOps or allowed to prevent the remaining digest.
@@ -4677,7 +4903,7 @@ turn.** It cannot execute operations or alter the audited history.
4677
4903
  | Scope | One interview for each worker with model-bearing inference turns; workers without inference evidence are omitted. |
4678
4904
  | Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. Quoted evidence is budgeted to the witness window ({§digest-requiem-evidence-budget}). |
4679
4905
  | Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
4680
- | Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as both `workerId` and `primaryWorkerId`, making the synthetic interview its own root without asserting a live worker topology. |
4906
+ | Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as the `workerId`, without asserting a live worker topology. |
4681
4907
  | Attempts | One call at `PLURNK_SERVICE_REQUIEM_MAX_TOKENS`; only an empty length-limited response receives one retry at `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS`. |
4682
4908
  | Artifacts | `requiem.md` carries testimony and exact nullable USD accounting. `requiem.json` is durably materialized before each call and preserves logical call state, messages, normalized responses, every physical request's state and accounting, and their shared aggregate projection. |
4683
4909
 
@@ -4697,9 +4923,9 @@ USD, and token totals across every physical exchange the turn paid for, failed
4697
4923
  calls included. It is the shared exact derivation from the ledger, never a second
4698
4924
  stored fact, so a live watcher accrues running loop cost per turn (#465).
4699
4925
 
4700
- §notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's exact `ops:///<loop>/<turn>` source. A bounded hard parse error becomes a durable failed operation whose Problem Details preserve its line, column, source, and parser-owned diagnostic. Hard errors that make the frame untrustworthy remain only with their rejected forensic attempt.
4926
+ §notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's exact `ops://<worker>/<loop>/<turn>` source. A bounded hard parse error becomes a durable failed operation whose Problem Details preserve its line, column, source, and parser-owned diagnostic. Hard errors that make the frame untrustworthy remain only with their rejected forensic attempt.
4701
4927
 
4702
- ### §tools Executable tool resources
4928
+ ### Executable tool resources
4703
4929
 
4704
4930
  §tools-resource-discovery **Executable capability discovery uses ordinary
4705
4931
  Plurnk resources.** No generated tool table rides the system packet. Every
@@ -4716,7 +4942,9 @@ preserve the full tool description and raw input schema under
4716
4942
  {§executor-input-schema-preview}; their nested paths do not contribute extra
4717
4943
  Turn0 rows. A schema-backed general runtime uses `<runtime>/input.md`.
4718
4944
  Non-schema targets retain supplemental details in family sections.
4719
- Tool-result/output schemas remain ordinary evidence, not teaching.
4945
+ Tool-result/output schemas remain ordinary evidence, not teaching. Unknown-target
4946
+ recovery names the published family document through the same path owner as
4947
+ materialization, including a runtime's declared `resourcesPath`.
4720
4948
 
4721
4949
  ```mermaid
4722
4950
  flowchart LR
@@ -4781,7 +5009,7 @@ untracked, absent); a glob previews what `add` would include or exclude. Names o
4781
5009
  content; nothing is added.
4782
5010
 
4783
5011
  §members-configuration *Available definitions.* The operator's `PLURNK_MEMBERS_<ALIAS>=<glob>`
4784
- (`!glob` excludes) and `PLURNK_MEMBERS_ENABLED=[…]` (absent or `[]` enables none) are the
5012
+ (`!glob` excludes) and `PLURNK_MEMBERS_ENABLED=[…]` (`[]` enables none) are the
4785
5013
  service-origin definitions, the shape `PLURNK_MCP_*` already has; an empty glob, a bare `!`,
4786
5014
  or an unknown enabled alias fails the daemon at boot.
4787
5015
 
@@ -4840,7 +5068,9 @@ contributes nothing and is refused with 400.
4840
5068
 
4841
5069
  *Admission.* `add {alias, definition}` requires `alias = name`, a `source`,
4842
5070
  and a project root when `scope` is `project`; the workspace definition may
4843
- shadow a service skill of the same name.
5071
+ shadow a service skill of the same name. The family's aliases use the standard
5072
+ skill-name grammar ({§agent-skills-name}), including digit-leading and Unicode
5073
+ names, rather than the coordinator's generic default.
4844
5074
 
4845
5075
  *Preparation.* For each enabled alias the adapter selects the host-provided
4846
5076
  tree for `service` scope or locates the directory at the filesystem scope;
@@ -4867,6 +5097,9 @@ The family exposes enabled, available {§agent-skills-tree} sources through
4867
5097
  `skill://<name>/`. The source owns its bytes; commons entries are demand-loaded
4868
5098
  projections, not writable installations. Filesystem skills retain their original
4869
5099
  directories; service-provided trees need no generated filesystem directory.
5100
+ The authority is the name's WHATWG URI representation, including percent-encoding
5101
+ for non-ASCII names. Installation names remain unchanged; a raw spelling and its
5102
+ serialized URI address the same resource, not separate skill identities.
4870
5103
 
4871
5104
  | Operation | Contract |
4872
5105
  | --- | --- |
@@ -4885,7 +5118,7 @@ An uninstalled Git skill is not manufactured by repository detection.
4885
5118
 
4886
5119
  §plurnk-skill **Plurnk's own reference is an ordinary service-provided skill.**
4887
5120
  `skill://plurnk/SKILL.md` is the standard frontmatter entry point, catalogued with
4888
- other enabled skills. It links package-owned configuration and model chapters,
5121
+ other enabled skills. It links package-owned configuration, model, and COPY/MOVE chapters,
4889
5122
  the complete `.env.defaults` aggregate at `skill://plurnk/.env.defaults`, and the
4890
5123
  Worker's existing tool/resource references. No chapter or defaults body is
4891
5124
  injected merely because the skill is enabled. The defaults bytes come from the
@@ -4920,7 +5153,7 @@ same exact 403 from dispatch rather than a second documentation policy.
4920
5153
  Optional non-execution operations remain a separate `## Enabled Optional Operations`
4921
5154
  section because they are language extensions rather than executable tools.
4922
5155
 
4923
- ### §schemes Scheme-reference discovery
5156
+ ### Scheme-reference discovery
4924
5157
 
4925
5158
  §schemes-directory Scheme references are ordinary workspace entries at `worker:///_plurnk/plurnk/<scheme>.md`. Turn0's FIND survey projects their summaries ({§worker-initialization-entry}); the model READs details on demand. No Resources section or separate example catalog is injected into the system packet.
4926
5159
 
@@ -4938,7 +5171,7 @@ section because they are language extensions rather than executable tools.
4938
5171
 
4939
5172
  ### §policy system.policy — the client's policy injection
4940
5173
 
4941
- §policy-sections One section rides the system slot **after the definition**: the contents of `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}), with no engine-generated heading. The policy document owns its Markdown structure. Policy is the client's authoritative rules promoted into the privileged zone — NOT a log entry; the model cannot READ or KILL it. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker:///_plurnk/agents.md` entry ({§turn0-agents-stunt}); references and skills use native discovery ({§skills-functionality}).
5174
+ §policy-sections One section rides the system slot **after the definition**: the contents of `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}), with no engine-generated heading. The policy document owns its Markdown structure. Policy is the client's authoritative rules promoted into the privileged zone — NOT a log entry; the model cannot READ or KILL it. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker:///_plurnk/AGENTS.md` entry ({§turn0-agents-stunt}); references and skills use native discovery ({§skills-functionality}).
4942
5175
 
4943
5176
  On first run, and only when `$XDG_CONFIG_HOME/plurnk` itself is absent, the service seeds
4944
5177
  `AGENTS.md` from `@plurnk/plurnk-meta/POLICY.md` ({§teaching-corpus}).
@@ -4966,7 +5199,7 @@ the transition.
4966
5199
  When Git is admitted for the workspace, `## Git Status` contains a Markdown
4967
5200
  `> [!NOTE]` block. Its quoted lines report the current
4968
5201
  branch, upstream ahead/behind counts, and staged/unstaged/untracked totals, then
4969
- one bounded line per non-empty class (at most eight paths, `+K more`): staged,
5202
+ one bounded line per non-empty class (at most `PLURNK_SERVICE_GIT_STATUS_PATHS` paths, `+K more`): staged,
4970
5203
  unstaged, `untracked members` — each path with the inclusion pattern that admits it or
4971
5204
  `created` for a creation record — and `untracked (not members)`, named because such a
4972
5205
  file is not a member ({§membership-baseline}) and a human must `git add` it or add a
@@ -4976,6 +5209,10 @@ the runtime actor's durable causal evidence: its `source=file` row carries
4976
5209
  the exact two-character porcelain `XY` value as `git` metadata when the status
4977
5210
  snapshot names that path. The engine takes one snapshot after membership
4978
5211
  reconciliation and uses it for both projections; no per-file Git process exists.
5212
+ Porcelain v2 NUL-delimited records supply these facts: an unborn branch retains
5213
+ its actual name with `no commits`; detached HEAD is identified as detached,
5214
+ never as a branch named `HEAD`. Pathnames and rename sources retain their exact
5215
+ bytes; the internal two-character status uses spaces for unchanged coordinates.
4979
5216
 
4980
5217
  ### §recap Optional Recap footer
4981
5218
 
@@ -4988,7 +5225,7 @@ one dormant authored source. A failed read fails packet assembly with its cause.
4988
5225
  The footer is one projection path and one authored source, not a second language
4989
5226
  contract.
4990
5227
 
4991
- ## §matcher Matcher selection and text regions
5228
+ ## Matcher selection and text regions
4992
5229
 
4993
5230
  Matchers select resources and report evidence; text scopes independently
4994
5231
  address the exact readable text, regardless of mimetype. Syntax belongs to
@@ -5050,7 +5287,7 @@ one binary marker to fail a repository-wide text search.
5050
5287
  Glob anchoring (`TODO*` starts-with, `*TODO*` contains, `*.log` ends-with,
5051
5288
  `[Tt]odo*` character class) lives in the mimetypes framework.
5052
5289
 
5053
- ### §matcher-result Matcher selection and evidence
5290
+ ### Matcher selection and evidence
5054
5291
 
5055
5292
  - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{channel?,locator?,region?}`; `channel` names the entry channel the finding was located in and is absent for channel-less resources such as log rows, so line coordinates cannot be mis-attributed across channels of the same resource ({§channel-selection-visibility}). `locator` preserves a structural address without overloading the resource row's `path`; `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. FIND alone decides whether that grouped selection projects as resource rows or flat locations ({§find-result-projection}); the engine never fabricates a region or guesses which surgical READ the model wants.
5056
5293
 
@@ -5132,7 +5369,7 @@ an existing channel retain its stored type. Effective mimetype is stored in
5132
5369
  `entry_channels.mimetype` and drives matcher, projection, and binary handling.
5133
5370
  Text scope meaning does not vary by mimetype.
5134
5371
 
5135
- ### §render-rule Render rule
5372
+ ### Render rule
5136
5373
 
5137
5374
  §render-rule-line-navigable-prefix Every textual content body with a source
5138
5375
  `startLine` renders with a coordinate prefix on each physical line, independent
@@ -5147,13 +5384,13 @@ presentation aid, never part of canonical content; matchers and mutations
5147
5384
  consume canonical bytes before rendering. A producer may set `startLine: null`
5148
5385
  only when its content is already source-numbered, such as an effect receipt.
5149
5386
 
5150
- §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, actionless source artifacts, prompt, and extension result content comes from `rx.content`; EDIT and scoped entry KILL use their structured receipt, while environment-delta EDIT uses its resulting span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; TASK serializes their canonical inventory through the shared {§json-result-rendering} spread as `application/json`; executions and SEND/WORK/FORK use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and the coordinate projection in {§render-rule-line-navigable-prefix}. READ/FIND over `log:///` and search use the same body with deliberate trims applied under {§log-readable-projection}, without packet-only suppression or preview limits. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
5387
+ §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, actionless source artifacts, prompt, and extension result content comes from `rx.content`; EDIT and scoped entry KILL use their structured receipt, while environment-delta EDIT uses its resulting span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; NOTE and lifecycle operations retain their literal `text/plain` bodies; executions and SEND/WORK/FORK use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and the coordinate projection in {§render-rule-line-navigable-prefix}. READ/FIND over `log:///` and search use the same body with deliberate trims applied under {§log-readable-projection}, without packet-only suppression or preview limits. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
5151
5388
 
5152
5389
  An EDIT or scoped entry KILL log row renders its bounded effect receipt (`rx.receipt`) as row
5153
5390
  metadata and join context, not its input statement. Proposal-gated file EDITs
5154
5391
  compute the accepted receipt from what actually lands. Environment-delta EDITs
5155
5392
  render their resulting `rx.span`. COPY/MOVE rows render compact ordered
5156
- `source` and `destination` selections, compact ordered `effects` metadata, and
5393
+ `from` and `to` selections ({§log-address-metadata}), compact ordered `effects` metadata, and
5157
5394
  any scoped textual receipt contexts under their `log:///` address, never under
5158
5395
  one operand's resource address. All generated bodies remain under
5159
5396
  {§body-projection}. {§edit-result-render}
@@ -5195,7 +5432,7 @@ Carried from the contract walk; durable.
5195
5432
  Any scoped textual transfer materializes create/update receipts; whole-channel
5196
5433
  changes do not. Operand selections remain independently visible per
5197
5434
  {§copy-move-observation}.
5198
- - **READ rx** prefixes every textual line under {§render-rule}; eligible
5435
+ - **READ rx** prefixes every textual line under {§render-rule-line-navigable-prefix}; eligible
5199
5436
  editable resources carry `@hash N:`, and all others carry `N:`.
5200
5437
  - **FIND pattern** (`[{"pattern": …}]` in the heading, {§matcher-option}) applies to the addressed entry channel (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). The target scope and channel select candidates; the path-glob is the (target). On READ, EDIT, KILL, COPY and MOVE the same heading pattern selects lines within one resource ({§read-pattern}, {§edit-pattern}, {§kill-pattern}, {§copy-move-pattern}).
5201
5438
  - **Scoped KILL** on the **log** (`log:///`) removes a body span from its readable projection ({§log-kill-scope}); on an entry it deletes that span through the EDIT path ({§kill-scope-entry}). A whole-entry KILL deletes the entry, or one `#fragment` channel.
@@ -5209,7 +5446,7 @@ A KILL with a text-coordinate scope aimed at an entry-bearing scheme deletes exa
5209
5446
 
5210
5447
  ---
5211
5448
 
5212
- ## §test-taxonomy Testing and evidence
5449
+ ## Testing and evidence
5213
5450
 
5214
5451
  | Tier | Location | LLM | Substrate |
5215
5452
  |---|---|---|---|
@@ -5241,15 +5478,13 @@ execution. The ledger and classification taxonomy live in
5241
5478
  distinct from model failures and repeated stochastic failures separately from
5242
5479
  stable ones, never with weakened assertions.
5243
5480
 
5244
- §test-artifact-retention **File-backed test databases use lane-local current-run
5245
- retention.** Each workspace's normal intg runner clears its own
5246
- `test/intg/.tmp/` once before the suite, reports that forensic directory, and
5247
- retains every artifact the current run creates; a direct `node --test <file>` run bypasses that
5248
- runner, so each test process prunes artifacts older than a day once, and never the current run's. A cross-package test may reuse
5249
- Core's migration fixture only by passing a path inside the caller's artifact
5250
- directory; independently scheduled lanes never share a reset target. A failed
5251
- suite therefore leaves its own evidence intact, and the next normal run of that
5252
- lane removes it before creating anything. Direct `node --test` invocations
5253
- bypass the runner boundary and must invoke the same cleanup procedure
5254
- explicitly when isolation matters. Live/demo run directories are benchmark
5255
- artifacts outside `.tmp` and retain their separate lifecycle.
5481
+ §test-artifact-retention **Every harness writes its run into one home.** A file-backed test
5482
+ database is a benchmark artifact like any other: the lane's run directory lives under
5483
+ `PLURNK_BENCHMARKS` (`~/benchmarks` by default) beside live, demo and benchlet runs, and the
5484
+ checkout holds source only — never run output. `test:intg` stamps `PLURNK_TEST_RUN` once and every
5485
+ test process inherits it, so one suite's databases land in one directory without a pretest step, a
5486
+ marker file or a sweep; an unstamped invocation is not a special case with its own rules, it is
5487
+ simply an unstamped run with its own directory. Nothing counts, reuses, moves, hides or
5488
+ conditionally clears an artifact, so a failed suite's evidence is exactly where the run reported
5489
+ it. A cross-package test may reuse Core's migration fixture only by passing a path inside the
5490
+ caller's own run directory.