@plurnk/plurnk-service 1.4.0 → 1.6.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 (302) hide show
  1. package/.env.defaults +37 -31
  2. package/INSTALL.md +16 -11
  3. package/README.md +1 -0
  4. package/SPEC.md +631 -397
  5. package/dist/Paths.d.ts.map +1 -1
  6. package/dist/Paths.js +2 -3
  7. package/dist/Paths.js.map +1 -1
  8. package/dist/build-info.json +1 -1
  9. package/dist/content/edit-collision.d.ts +5 -0
  10. package/dist/content/edit-collision.d.ts.map +1 -0
  11. package/dist/content/edit-collision.js +14 -0
  12. package/dist/content/edit-collision.js.map +1 -0
  13. package/dist/content/edit-receipt.d.ts +3 -2
  14. package/dist/content/edit-receipt.d.ts.map +1 -1
  15. package/dist/content/edit-receipt.js +58 -13
  16. package/dist/content/edit-receipt.js.map +1 -1
  17. package/dist/content/index.d.ts +5 -1
  18. package/dist/content/index.d.ts.map +1 -1
  19. package/dist/content/index.js +4 -1
  20. package/dist/content/index.js.map +1 -1
  21. package/dist/content/line-anchors.d.ts +41 -0
  22. package/dist/content/line-anchors.d.ts.map +1 -0
  23. package/dist/content/line-anchors.js +191 -0
  24. package/dist/content/line-anchors.js.map +1 -0
  25. package/dist/content/line-marker.d.ts +7 -3
  26. package/dist/content/line-marker.d.ts.map +1 -1
  27. package/dist/content/line-marker.js +2 -1
  28. package/dist/content/line-marker.js.map +1 -1
  29. package/dist/content/matcher.d.ts +1 -1
  30. package/dist/content/matcher.d.ts.map +1 -1
  31. package/dist/content/matcher.js +2 -2
  32. package/dist/content/matcher.js.map +1 -1
  33. package/dist/content/read-projector.d.ts +20 -0
  34. package/dist/content/read-projector.d.ts.map +1 -0
  35. package/dist/content/read-projector.js +122 -0
  36. package/dist/content/read-projector.js.map +1 -0
  37. package/dist/content/read-resolve.d.ts +2 -7
  38. package/dist/content/read-resolve.d.ts.map +1 -1
  39. package/dist/content/read-resolve.js +32 -107
  40. package/dist/content/read-resolve.js.map +1 -1
  41. package/dist/core/BranchReceipt.d.ts +0 -1
  42. package/dist/core/BranchReceipt.d.ts.map +1 -1
  43. package/dist/core/BranchReceipt.js +0 -3
  44. package/dist/core/BranchReceipt.js.map +1 -1
  45. package/dist/core/BudgetReadout.d.ts.map +1 -1
  46. package/dist/core/BudgetReadout.js +9 -2
  47. package/dist/core/BudgetReadout.js.map +1 -1
  48. package/dist/core/ChannelWrite.d.ts +3 -0
  49. package/dist/core/ChannelWrite.d.ts.map +1 -1
  50. package/dist/core/ChannelWrite.js +3 -3
  51. package/dist/core/ChannelWrite.js.map +1 -1
  52. package/dist/core/ChannelWrite.sql +4 -3
  53. package/dist/core/CoreSchemeServices.d.ts +10 -2
  54. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  55. package/dist/core/CoreSchemeServices.js.map +1 -1
  56. package/dist/core/Dispatcher.d.ts +14 -8
  57. package/dist/core/Dispatcher.d.ts.map +1 -1
  58. package/dist/core/Dispatcher.js +656 -312
  59. package/dist/core/Dispatcher.js.map +1 -1
  60. package/dist/core/DurableStatement.d.ts.map +1 -1
  61. package/dist/core/DurableStatement.js +2 -0
  62. package/dist/core/DurableStatement.js.map +1 -1
  63. package/dist/core/Engine.d.ts +24 -18
  64. package/dist/core/Engine.d.ts.map +1 -1
  65. package/dist/core/Engine.js +620 -392
  66. package/dist/core/Engine.js.map +1 -1
  67. package/dist/core/Engine.sql +188 -119
  68. package/dist/core/ExecutableTools.d.ts +10 -0
  69. package/dist/core/ExecutableTools.d.ts.map +1 -0
  70. package/dist/core/ExecutableTools.js +41 -0
  71. package/dist/core/ExecutableTools.js.map +1 -0
  72. package/dist/core/ExecutorRegistry.d.ts +3 -3
  73. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  74. package/dist/core/ExecutorRegistry.js +2 -2
  75. package/dist/core/ExecutorRegistry.js.map +1 -1
  76. package/dist/core/LogBody.d.ts +4 -1
  77. package/dist/core/LogBody.d.ts.map +1 -1
  78. package/dist/core/LogBody.js +46 -2
  79. package/dist/core/LogBody.js.map +1 -1
  80. package/dist/core/LogEntryProjection.d.ts +14 -0
  81. package/dist/core/LogEntryProjection.d.ts.map +1 -0
  82. package/dist/core/LogEntryProjection.js +38 -0
  83. package/dist/core/LogEntryProjection.js.map +1 -0
  84. package/dist/core/LoopLifecycle.d.ts +1 -2
  85. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  86. package/dist/core/LoopLifecycle.js +1 -4
  87. package/dist/core/LoopLifecycle.js.map +1 -1
  88. package/dist/core/LoopLifecycle.sql +1 -4
  89. package/dist/core/ModelCall.d.ts +27 -0
  90. package/dist/core/ModelCall.d.ts.map +1 -0
  91. package/dist/core/ModelCall.js +125 -0
  92. package/dist/core/ModelCall.js.map +1 -0
  93. package/dist/core/PacketBuilder.d.ts +13 -12
  94. package/dist/core/PacketBuilder.d.ts.map +1 -1
  95. package/dist/core/PacketBuilder.js +146 -118
  96. package/dist/core/PacketBuilder.js.map +1 -1
  97. package/dist/core/ProblemLog.d.ts.map +1 -1
  98. package/dist/core/ProblemLog.js +1 -0
  99. package/dist/core/ProblemLog.js.map +1 -1
  100. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  101. package/dist/core/ProposalLifecycle.js +3 -4
  102. package/dist/core/ProposalLifecycle.js.map +1 -1
  103. package/dist/core/ProviderInstantiate.d.ts.map +1 -1
  104. package/dist/core/ProviderInstantiate.js +23 -6
  105. package/dist/core/ProviderInstantiate.js.map +1 -1
  106. package/dist/core/SchemeRegistry.js +7 -7
  107. package/dist/core/SchemeRegistry.js.map +1 -1
  108. package/dist/core/StrikeRail.d.ts +5 -2
  109. package/dist/core/StrikeRail.d.ts.map +1 -1
  110. package/dist/core/StrikeRail.js +10 -7
  111. package/dist/core/StrikeRail.js.map +1 -1
  112. package/dist/core/TerminalResult.d.ts +16 -0
  113. package/dist/core/TerminalResult.d.ts.map +1 -0
  114. package/dist/core/TerminalResult.js +49 -0
  115. package/dist/core/TerminalResult.js.map +1 -0
  116. package/dist/core/caps/CapsResolve.d.ts +5 -1
  117. package/dist/core/caps/CapsResolve.d.ts.map +1 -1
  118. package/dist/core/caps/CapsResolve.js +9 -5
  119. package/dist/core/caps/CapsResolve.js.map +1 -1
  120. package/dist/core/caps/DbChannelCaps.d.ts +1 -1
  121. package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
  122. package/dist/core/caps/DbChannelCaps.js +6 -4
  123. package/dist/core/caps/DbChannelCaps.js.map +1 -1
  124. package/dist/core/caps/DbEntryCaps.d.ts +2 -1
  125. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
  126. package/dist/core/caps/DbEntryCaps.js +21 -8
  127. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  128. package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
  129. package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
  130. package/dist/core/caps/DbNotifyCaps.js +6 -4
  131. package/dist/core/caps/DbNotifyCaps.js.map +1 -1
  132. package/dist/core/caps/DbProjectionCaps.d.ts +1 -0
  133. package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
  134. package/dist/core/caps/DbProjectionCaps.js +29 -0
  135. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  136. package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -6
  137. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
  138. package/dist/core/caps/DbSubscriptionCaps.js +27 -13
  139. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
  140. package/dist/core/caps/SchemeCtxImpl.d.ts +11 -3
  141. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
  142. package/dist/core/caps/SchemeCtxImpl.js +10 -8
  143. package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
  144. package/dist/core/fork.d.ts.map +1 -1
  145. package/dist/core/fork.js +23 -7
  146. package/dist/core/fork.js.map +1 -1
  147. package/dist/core/fork.sql +35 -14
  148. package/dist/core/git-iso.d.ts +3 -2
  149. package/dist/core/git-iso.d.ts.map +1 -1
  150. package/dist/core/git-iso.js +27 -12
  151. package/dist/core/git-iso.js.map +1 -1
  152. package/dist/core/git-membership.d.ts +1 -0
  153. package/dist/core/git-membership.d.ts.map +1 -1
  154. package/dist/core/git-membership.js +87 -26
  155. package/dist/core/git-membership.js.map +1 -1
  156. package/dist/core/git-state.d.ts +8 -1
  157. package/dist/core/git-state.d.ts.map +1 -1
  158. package/dist/core/git-state.js +36 -17
  159. package/dist/core/git-state.js.map +1 -1
  160. package/dist/core/namespace.d.ts +1 -0
  161. package/dist/core/namespace.d.ts.map +1 -1
  162. package/dist/core/namespace.js +20 -0
  163. package/dist/core/namespace.js.map +1 -1
  164. package/dist/core/optimistic-settlement.d.ts +2 -0
  165. package/dist/core/optimistic-settlement.d.ts.map +1 -0
  166. package/dist/core/optimistic-settlement.js +14 -0
  167. package/dist/core/optimistic-settlement.js.map +1 -0
  168. package/dist/core/packet-wire.d.ts +5 -2
  169. package/dist/core/packet-wire.d.ts.map +1 -1
  170. package/dist/core/packet-wire.js +318 -114
  171. package/dist/core/packet-wire.js.map +1 -1
  172. package/dist/core/provider-accounting.d.ts +24 -0
  173. package/dist/core/provider-accounting.d.ts.map +1 -0
  174. package/dist/core/provider-accounting.js +76 -0
  175. package/dist/core/provider-accounting.js.map +1 -0
  176. package/dist/core/results.d.ts +4 -2
  177. package/dist/core/results.d.ts.map +1 -1
  178. package/dist/core/results.js +6 -0
  179. package/dist/core/results.js.map +1 -1
  180. package/dist/core/scheme-types.d.ts +0 -12
  181. package/dist/core/scheme-types.d.ts.map +1 -1
  182. package/dist/core/scheme-types.js.map +1 -1
  183. package/dist/core/search-gate.d.ts +2 -2
  184. package/dist/core/search-gate.d.ts.map +1 -1
  185. package/dist/core/search-gate.js +8 -8
  186. package/dist/core/search-gate.js.map +1 -1
  187. package/dist/core/token-ruler.js +1 -1
  188. package/dist/core/token-ruler.js.map +1 -1
  189. package/dist/core/turn-scheduler.js +1 -1
  190. package/dist/core/turn-scheduler.js.map +1 -1
  191. package/dist/core/worker-ops.sql +4 -4
  192. package/dist/core/workspace-settings.js +1 -1
  193. package/dist/core/workspace-settings.js.map +1 -1
  194. package/dist/digest/Digest.d.ts.map +1 -1
  195. package/dist/digest/Digest.js +349 -76
  196. package/dist/digest/Digest.js.map +1 -1
  197. package/dist/digest/digest.sql +42 -16
  198. package/dist/schemes/Exec.d.ts +4 -4
  199. package/dist/schemes/Exec.d.ts.map +1 -1
  200. package/dist/schemes/Exec.js +167 -134
  201. package/dist/schemes/Exec.js.map +1 -1
  202. package/dist/schemes/ExecOutputScheme.d.ts +4 -5
  203. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  204. package/dist/schemes/ExecOutputScheme.js +12 -20
  205. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  206. package/dist/schemes/File.d.ts +5 -6
  207. package/dist/schemes/File.d.ts.map +1 -1
  208. package/dist/schemes/File.js +35 -41
  209. package/dist/schemes/File.js.map +1 -1
  210. package/dist/schemes/Log.d.ts +16 -5
  211. package/dist/schemes/Log.d.ts.map +1 -1
  212. package/dist/schemes/Log.js +229 -262
  213. package/dist/schemes/Log.js.map +1 -1
  214. package/dist/schemes/Log.sql +50 -27
  215. package/dist/schemes/Prompt.d.ts +3 -4
  216. package/dist/schemes/Prompt.d.ts.map +1 -1
  217. package/dist/schemes/Prompt.js +5 -5
  218. package/dist/schemes/Prompt.js.map +1 -1
  219. package/dist/schemes/Skill.d.ts +4 -5
  220. package/dist/schemes/Skill.d.ts.map +1 -1
  221. package/dist/schemes/Skill.js +3 -3
  222. package/dist/schemes/Skill.js.map +1 -1
  223. package/dist/schemes/Worker.d.ts +7 -7
  224. package/dist/schemes/Worker.d.ts.map +1 -1
  225. package/dist/schemes/Worker.js +99 -84
  226. package/dist/schemes/Worker.js.map +1 -1
  227. package/dist/schemes/_entry-crud.d.ts +2 -2
  228. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  229. package/dist/schemes/_entry-crud.js +29 -10
  230. package/dist/schemes/_entry-crud.js.map +1 -1
  231. package/dist/schemes/_entry-crud.sql +11 -17
  232. package/dist/schemes/_entry-find.d.ts +41 -14
  233. package/dist/schemes/_entry-find.d.ts.map +1 -1
  234. package/dist/schemes/_entry-find.js +159 -166
  235. package/dist/schemes/_entry-find.js.map +1 -1
  236. package/dist/schemes/_entry-find.sql +2 -21
  237. package/dist/schemes/_entry-graph.sql +1 -1
  238. package/dist/schemes/_entry-manifest.d.ts +5 -17
  239. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  240. package/dist/schemes/_entry-manifest.js +28 -24
  241. package/dist/schemes/_entry-manifest.js.map +1 -1
  242. package/dist/schemes/_entry-ops.d.ts +13 -8
  243. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  244. package/dist/schemes/_entry-ops.js +98 -119
  245. package/dist/schemes/_entry-ops.js.map +1 -1
  246. package/dist/schemes/_entry-ops.sql +31 -6
  247. package/dist/schemes/_entry-semantic.d.ts +5 -7
  248. package/dist/schemes/_entry-semantic.d.ts.map +1 -1
  249. package/dist/schemes/_entry-semantic.js +10 -31
  250. package/dist/schemes/_entry-semantic.js.map +1 -1
  251. package/dist/schemes/_entry-semantic.sql +2 -2
  252. package/dist/schemes/_entry-send.js +4 -4
  253. package/dist/schemes/_entry-send.js.map +1 -1
  254. package/dist/schemes/_search-index.d.ts.map +1 -1
  255. package/dist/schemes/_search-index.js +16 -6
  256. package/dist/schemes/_search-index.js.map +1 -1
  257. package/dist/schemes/exec-abort.js +2 -2
  258. package/dist/schemes/exec-abort.js.map +1 -1
  259. package/dist/server/BranchBatches.d.ts +1 -0
  260. package/dist/server/BranchBatches.d.ts.map +1 -1
  261. package/dist/server/BranchBatches.js +1 -0
  262. package/dist/server/BranchBatches.js.map +1 -1
  263. package/dist/server/Daemon.d.ts +6 -8
  264. package/dist/server/Daemon.d.ts.map +1 -1
  265. package/dist/server/Daemon.js +238 -68
  266. package/dist/server/Daemon.js.map +1 -1
  267. package/dist/server/DaemonModule.d.ts +3 -3
  268. package/dist/server/DaemonModule.d.ts.map +1 -1
  269. package/dist/server/branch-batch.sql +3 -1
  270. package/dist/server/client-input.d.ts +2 -1
  271. package/dist/server/client-input.d.ts.map +1 -1
  272. package/dist/server/client-input.js +7 -1
  273. package/dist/server/client-input.js.map +1 -1
  274. package/dist/server/drain.sql +8 -7
  275. package/dist/server/envelope.d.ts +0 -2
  276. package/dist/server/envelope.d.ts.map +1 -1
  277. package/dist/server/envelope.js +0 -1
  278. package/dist/server/envelope.js.map +1 -1
  279. package/dist/server/envelope.sql +3 -4
  280. package/dist/server/lifecycle-recovery.sql +44 -1
  281. package/dist/server/logEntry.d.ts +2 -1
  282. package/dist/server/logEntry.d.ts.map +1 -1
  283. package/dist/server/logEntry.js +15 -2
  284. package/dist/server/logEntry.js.map +1 -1
  285. package/dist/server/logEntry.sql +5 -1
  286. package/dist/service.d.ts.map +1 -1
  287. package/dist/service.js +13 -1
  288. package/dist/service.js.map +1 -1
  289. package/migrations/001_schema.sql +730 -221
  290. package/package.json +53 -46
  291. package/dist/core/BudgetOverflow.d.ts +0 -23
  292. package/dist/core/BudgetOverflow.d.ts.map +0 -1
  293. package/dist/core/BudgetOverflow.js +0 -61
  294. package/dist/core/BudgetOverflow.js.map +0 -1
  295. package/dist/core/caps/DbTagCaps.d.ts +0 -10
  296. package/dist/core/caps/DbTagCaps.d.ts.map +0 -1
  297. package/dist/core/caps/DbTagCaps.js +0 -44
  298. package/dist/core/caps/DbTagCaps.js.map +0 -1
  299. package/dist/matrix/live-specimen.d.ts +0 -9
  300. package/dist/matrix/live-specimen.d.ts.map +0 -1
  301. package/dist/matrix/live-specimen.js +0 -37
  302. package/dist/matrix/live-specimen.js.map +0 -1
package/SPEC.md CHANGED
@@ -26,11 +26,12 @@ flowchart LR
26
26
  | **agent** | PLURNK | The plurnk runtime. Acts in-workspace as the reserved `plurnk` worker ({§actor-boundary} self-hosting), never a privileged singleton owning its own entries ({§entry-owner}, {§machine-processes}). |
27
27
  | **workspace** | Core | Durable user-named shared world. Persists across workers and process restarts. Identity: `workspaces.id` + unique `workspaces.name`. |
28
28
  | **worker** | Core | Durable actor and private history over one workspace. Owns its loops and log rows, may carry a `parent_worker_id`, and has one process-local cancellation scope while active. |
29
- | **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 budget-overflow · 429 turn-ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
29
+ | **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 context-envelope rejection · 429 turn-ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
30
30
  | **turn** | Core | One engine scheduling unit (or one client-op scheduling unit). A model turn sends one assembled prompt through one or more emission attempts and admits at most one response. Many turns may belong to one loop. Identity: `(loop_id, sequence)`. |
31
+ | **model call** | Core/provider | One logical `provider.generate` invocation. Emission attempts and BARE inferences share this durable accounting owner; provider retries remain cardinal physical requests beneath it. Identity: `(turn_id, sequence)`. |
31
32
  | **op** | Model/core | One DSL operation the model emits, parsed into a `PlurnkStatement`. One admitted turn produces zero or more ops. |
32
33
  | **statement** | Model/core | A parsed op: the `PlurnkStatement` AST from `@plurnk/plurnk-contracts`. |
33
- | **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an actionless `op='error'` row ({§operation-results}). |
34
+ | **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an actionless `op='error'` row ({§operation-results}). Actionless artifacts carry no fabricated operation. |
34
35
  | **dispatch** | Core | Routing a statement to its scheme's op handler. |
35
36
  | **AG-UI Run** | AG-UI protocol | A client request/stream envelope identified by the client's `runId`. A message or resume AG-UI Run binds to one core loop; a management-action AG-UI Run may complete without creating a core loop. |
36
37
  | **AG-UI thread** | AG-UI protocol | Conversation identity. Within an explicitly selected workspace, `threadId` resolves to one conversation worker. |
@@ -41,7 +42,7 @@ flowchart LR
41
42
 
42
43
  | Term | Meaning |
43
44
  |---|---|
44
- | **entry** | The unit of canonical state. Identity: `(workspace, owner, scheme, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus `tags` and `attributes`. |
45
+ | **entry** | The unit of canonical state. Identity: `(workspace, owner, scheme, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus private `attributes`. |
45
46
  | **channel** | A named content buffer on an entry. Examples: `body`, `stdout`, `stderr`, `headers`, `symbols`. Each channel has `content`, `mimetype`, `tokens`, `state`. |
46
47
  | **scope** | A scheme-manifest declaration ignored by core; registrations are discovered at boot and are not persisted. Entry sharing and privacy are owner-based; #80 owns retiring this residual axis. |
47
48
  | **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 the EXEC op but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
@@ -75,11 +76,14 @@ These are the complete strike sources:
75
76
 
76
77
  | Strike source | Exact trigger | Model-visible occurrence |
77
78
  |---------------------|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
78
- | Hard result | An admitted operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `501`. | The originating failure row. |
79
- | Grinder | Packet overflow caused a grinder fold or admitted hard-recovery turn ({§grinder-strike-coupling}). | The exact overflow Problem row. |
80
- | Terminal steering | An idle `SEND[102]` or a final disposition refused at 409 sets the turn's steering ruling ({§send}). | The idle rail row or refused SEND row. |
79
+ | Hard result | An admitted non-`EXEC` operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `501`. | The originating failure row. |
80
+ | Terminal steering | An idle SEND with signal `102` or a final disposition refused at 409 sets the turn's steering ruling ({§send}). | The idle rail row or refused SEND row. |
81
81
  | Cycle | The configured consecutive fingerprint pattern repeats. | None; cycle detection itself is private engine accounting. |
82
82
 
83
+ `EXEC` results remain exact model-visible evidence but are always soft: an
84
+ executor error is not a PLURNK contract violation. Cycle and terminal steering
85
+ remain independent strike sources.
86
+
83
87
  A struck turn increments the consecutive streak once; a clean admitted turn
84
88
  resets it to zero. Reaching `MAX_STRIKES` terminates at **508 Loop Detected**
85
89
  when the crossing turn is cycle-detected, otherwise **500**. Rejected emission
@@ -94,6 +98,7 @@ shown. The current streak may ride first-party provider metadata
94
98
  | **verdict** | The end-of-turn ruling computed inline in `Engine.runLoop` from the strike rail and independent loop terminals. No filter chain. |
95
99
  | **strike** | One admitted turn matching at least one source above. |
96
100
  | **emission attempt** | One completed provider exchange beneath an engine turn. ANTLR admits it when it has a trustworthy PLAN...SEND frame and no boundary-destroying tail. A hard error bounded to an interior statement becomes a failed operation inside the admitted turn; a rejected attempt is forensic evidence, not another turn or an engine strike. |
101
+ | **BARE inference** | One body-only child-provider model call whose response becomes an ordinary BARE log result. It has no worker, packet, tools, output grammar, or persistent child state ({§bare-inference}). |
97
102
  | **cycle** | A repeated turn fingerprint across consecutive turns. Detection strikes silently under the rule above. |
98
103
  | §mode-ask-read-only **mode** | `"ask" \| "act"`. Per-loop. Ask = read-only: the dispatch gate refuses every side-effecting op (a filesystem write — EDIT/COPY-dest/MOVE/KILL on the `file` scheme — or any EXEC invocation); reads of the workspace stay open. `act` = full surface. Ask never changes the world. |
99
104
  | **flag** | Per-loop value: `mode`, `noWeb`, and `noInteraction` shape scheme authority ({§manifest-flag-affinity}); `auto` and `noProposals` select proposal settlement. |
@@ -122,9 +127,10 @@ real PLURNK loop: the production packet, a model-selected operation, its
122
127
  materialized result, and completion.** Transport-only completions are not
123
128
  conformance evidence. Provider-exposed reasoning must survive in the durable
124
129
  assistant packet and digest; a provider with no private reasoning is valid when
125
- the observable operation cycle succeeds. The maintained procedure runs one
126
- named live specimen deterministically (`npm run test:live:specimen -- <pattern>`
127
- in plurnk-core); the ledger and classification taxonomy live in
130
+ the observable operation cycle succeeds. One package-owned runner executes the
131
+ full tier or exactly one registered specimen (`npm run test:live:specimen --
132
+ <exact test name>` in plurnk-core), rejecting absent and duplicate names before
133
+ execution. The ledger and classification taxonomy live in
128
134
  `plurnk-providers/README.md` and report authorization/credential failures
129
135
  distinct from model failures and repeated stochastic failures separately from
130
136
  stable ones, never with weakened assertions.
@@ -226,7 +232,7 @@ preserving the originating failure.
226
232
  flowchart LR
227
233
  actor["Worker A"] -->|"shared file or shared entry op"| state["Shared project files<br/>and shared workspace entries"]
228
234
  state -->|"folded attributed delta<br/>environment door"| log["Worker B log"]
229
- actor -->|"SEND(worker://B)<br/>voice door"| log
235
+ actor -->|"SEND to worker B<br/>voice door"| log
230
236
  client["User / client"] -->|"loop.inject<br/>voice door"| log
231
237
  ```
232
238
 
@@ -248,7 +254,7 @@ file or ancestry-authorized entry through ordinary dispatch ({§worker-read-scop
248
254
  | Door | Carries | Wake behavior |
249
255
  | ----------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
250
256
  | Environment | A change to a shared project file or shared worker entry, as a folded attributed delta. | Ambient state never wakes an idle worker ({§env-delta}). |
251
- | Voice | A directed `loop.inject` or `SEND(worker://name)` message. | An active worker folds it into its next turn; an idle one wakes. |
257
+ | Voice | A directed `loop.inject` or `## SEND0 (worker://name)` message. | An active worker folds it into its next turn; an idle one wakes. |
252
258
 
253
259
  §actor-boundary-no-mutex **Wild west by default; explicit branch batches are the exception.** Ordinary workers share workspace state without locks. Coordination is cooperative and softly fenced (the {§membership} `read-only` overlay, a workspace policy, bounds every worker's writable surface uniformly — {§machine-processes}); a conflict *surfaces* as a delta rather than being prevented. A branch-tagged WORK/FORK opts the whole workspace into the bounded, exclusive Git transaction in {§worker-branch-batch}. It is not a general entry mutex or a hidden per-worker filesystem.
254
260
 
@@ -285,7 +291,9 @@ the `plurnk` worker's log; the model sees the shared entry through its own READ.
285
291
  Client-provided workspace documents union with the operator set at the same
286
292
  entry surface.
287
293
 
288
- §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS` foists turn-0 FINDs into the worker's first turn, so a worker opens with a navigable map instead of blank. An enabled preview always executes four orienting surveys: project files (`FIND(*)`), workspace commons (`FIND(worker:///*)`), the worker's own space (`FIND(worker://~/*)`), and kernel docs (`FIND(worker://plurnk/docs/**)`). Folder-capable entry plugins use the same shallow form; a scheme without folder scopes remains recursive. A shallow result is complete, not truncated: direct entries render normally and every deeper first-segment directory renders as an actionable `dir/**` summary with its recursive `items` and `tokens`. The small curated kernel-doc surface remains recursively enumerated, so the opening exemplar demonstrates both `*` and `**`. Every survey executes even when empty because zero results are useful orientation. A positive `N` caps only the file map's rendered rows, using the map's actual direct-entry-plus-directory count; `-1` renders the complete shallow map; unset / `0` disables previews. `log://` is absent because the current worker's log already renders in present mode.
294
+ §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS` foists turn-0 FINDs into the worker's first turn, so a worker opens with a navigable map instead of blank. An enabled preview executes exactly four orienting surveys in order: project files (`## FIND0 [+init] (*)`), workspace commons (`## FIND0 [+init] (worker:///*)`), the worker's own space (`## FIND0 [+init] (worker://~/*)`), and kernel docs (`## FIND0 [+init,+docs] (worker://plurnk/docs/**) <1,-1>`). Their log classifications make the opening survey one `init` set while retaining `docs` on its documentation row ({§log-item-tags}). A shallow result renders direct entries normally and every deeper first-segment directory as an actionable `dir/**` summary with its recursive `items` and `tokens`. Ordinary surveys use FIND's markerless first-16 page, whose range metadata reports the requested and returned page against the complete result total; only the small curated kernel-doc surface explicitly selects all. The opening exemplar therefore demonstrates both `*` and `**` without normalizing an all-results override. Every survey executes even when empty because zero results are useful orientation. A positive `N` explicitly caps only the file map's rendered rows, using the map's actual direct-entry-plus-directory count; `-1` enables the ordinary markerless page; unset / `0` disables previews. `log://` is absent because the current worker's log already renders in present mode.
295
+
296
+ §worker-initialization-entry **Worker initialization is not model output.** A worker's first loop begins with one born-OPEN actionless row at `log:///1/1/1`: `origin="plurnk"`, `op` null, and `attrs.kind="initialization"`. Its `text/vnd.plurnk` body dynamically mirrors the turn-zero PLAN, the orienting operations actually dispatched, and terminal `SEND0 [102]`. The PLAN states `* Initialization complete.` and `* Next: address the prompt.`; SEND hands off with `Next, address the prompt.`
289
297
 
290
298
  ### §machine-processes The machine and its processes: workspace, worker, fork
291
299
 
@@ -321,8 +329,8 @@ terminal history.**
321
329
  | Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
322
330
  | Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
323
331
  | Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
324
- | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, tags, fold state, and the matching observation cursor are copied as terminal history. |
325
- | §machine-processes-fork-cost **Turn usage and cost** | Worker | Copied turns carry zero usage and cost; branch totals cover new generation only and workspace spend stays exact. |
332
+ | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, curation effects, tags, fold state, and the matching observation cursor are copied as terminal history. |
333
+ | §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but `model_calls`, emission-admission rows, and physical provider requests are not: one issued call or request has one owning worker. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
326
334
  | Private worker entries (`worker://~/...`) | Worker | Deep-copied with ownership remapped; parent and child then diverge. |
327
335
  | Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
328
336
 
@@ -339,6 +347,14 @@ therefore carries only shared project-file and shared-entry changes
339
347
 
340
348
  §machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `plurnk` (the runtime's self-hosting worker) — set once at creation and inherited by a fork. `listWorkers` returns it, so a client interface identifies actor class without parsing the name, which is set at instantiation and immutable (a worker is permanent history, {§machine-processes-worker-is-its-log}).
341
349
 
350
+ §worker-provider-identity **A worker owns a durable provider identity distinct
351
+ from its database id.** Creation mints a globally unique, opaque 128-bit value;
352
+ forks mint their own value. Core supplies it as the provider `workerId` for every
353
+ emission and supplies the lineage root's value as `primaryWorkerId`
354
+ ({§provider-cache-identity}). Database ids remain the internal relational and
355
+ client coordinate. BARE calls use isolated per-call provider identities rather
356
+ than either worker value.
357
+
342
358
  §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.
343
359
 
344
360
  §machine-processes-fork-shares-the-world **A fork copies worker-owned history
@@ -397,9 +413,9 @@ literal `workers.name` value.
397
413
  | `READ` | existing literal name | Collect the named worker's deliverable. |
398
414
  | `KILL` | existing literal name, `~` | Terminate the named worker or caller. |
399
415
 
400
- - §worker-scheme-spawn **Spawn** — `WORK(worker://<name>):task` creates a new worker sister (empty log) and starts it with `task` on its first loop. WORK/FORK are the worker-creation verbs (grammar 0.74.55): EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. A name is **frozen per worker** but **reclaimable across time** ({§machine-processes-worker-origin}): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `worker_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `worker '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error.
401
- - §worker-scheme-irc **irc** — `SEND(worker://<name>):msg` delivers `msg` to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). `SEND(worker://~):msg` targets the caller; a literal name with no worker in the workspace is 404.
402
- - §worker-scheme-fork **Fork** — `FORK(worker://<name>):task` branches the
416
+ - §worker-scheme-spawn **Spawn** — `## WORK0 (worker://<name>)` with a task body creates a new worker sister (empty log) and starts it with that task on its first loop. WORK/FORK are the worker-creation verbs: EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. A name is **frozen per worker** but **reclaimable across time** ({§machine-processes-worker-origin}): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `worker_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `worker '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error.
417
+ - §worker-scheme-irc **irc** — `## SEND0 (worker://<name>)` with a message body delivers it to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). `## SEND0 (worker://~)` targets the caller; a literal name with no worker in the workspace is 404.
418
+ - §worker-scheme-fork **Fork** — `## FORK0 (worker://<name>)` with a task body branches the
403
419
  current worker into a **named** sister: its log is deep-copied
404
420
  ({§machine-processes-fork-copies-the-log}), which continues with `task`; the
405
421
  world is shared, never copied ({§machine-processes-fork-shares-the-world}).
@@ -414,7 +430,7 @@ literal `workers.name` value.
414
430
  parent's private entries — its own space deep-copied with the owner
415
431
  remapped (source → branch) — so the branch opens with the parent's notes and
416
432
  diverges on its own edits: *fork = everything-in-common-but-name*.
417
- - **Git branch batch** — `WORK[feature/x](worker://<name>):task` and `FORK[feature/x](worker://<name>):task` retain their worker meanings while placing the child in the serialized Git transaction defined by {§worker-branch-batch}. The signal is one branch ref, not tags; an untagged WORK/FORK keeps the ordinary concurrent shared-world behavior.
433
+ - **Git branch batch** — `## WORK0 [feature/x] (worker://<name>)` and `## FORK0 [feature/x] (worker://<name>)`, each with a task body, retain their worker meanings while placing the child in the serialized Git transaction defined by {§worker-branch-batch}. The signal is one branch ref, not tags; an untagged WORK/FORK keeps the ordinary concurrent shared-world behavior.
418
434
  - §worker-delegation-inherits-flags **Delegation inherits authority.** The live loop a spawn, fork, or irc-raised fresh loop starts with carries the **delegating loop's flags** — an auto parent delegates auto workers. Flags are a property of the delegation, not of a client binding: a child loop that fell back to defaults could propose side effects into a resolver-less headless review queue. An irc that *resumes* a parked loop leaves that loop's own flags untouched — inheritance applies only where a fresh loop is born.
419
435
  - §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.
420
436
 
@@ -448,7 +464,7 @@ sequenceDiagram
448
464
  participant B as Branch batch
449
465
  participant C1 as Child branch 1
450
466
  participant C2 as Child branch 2
451
- P->>B: WORK[branch-1], FORK[branch-2]
467
+ P->>B: WORK branch-1, FORK branch-2
452
468
  P->>G: queue exclusive before releasing shared turn
453
469
  G-->>B: all earlier turns drained
454
470
  B->>B: snapshot clean project repository; create both refs from frozen base
@@ -464,30 +480,31 @@ sequenceDiagram
464
480
 
465
481
  §worker-branch-batch-preflight **Preflight is total.** `GitMembership.projectRepository` resolves the repository containing `project_root`; absence rejects the tagged op. Earlier turns and finite derivation work drain at the exclusive boundary; a pre-existing open stream subscription is not a finite checkout operation and therefore rejects preflight rather than being silently cancelled or waited forever. Before any child starts, every branch passes `git check-ref-format --branch`, the project repository has no staged, unstaged, or nonignored untracked changes, every requested branch is absent, and the original symbolic ref/detached commit is recorded. All branch refs are then created from that frozen commit. Failure rolls back only refs created by this preflight, fails the queued children, restores the parent, and releases the workspace. Existing branches are never adopted or overwritten.
466
482
 
467
- §worker-branch-batch-return **A child returns commits, never a dirty checkout.** SEND[200], SEND[499], and an already-drained SEND[202] are refused with 409 while the project repository is off the assigned branch or dirty. The model commits or deliberately discards its changes and concludes again. On terminal, the batch records the full result commit and whether it differs from the frozen base, restores the exact original ref and commit, and only then advances. A clean child failure is a completed batch item and does not suppress later siblings; an ambiguous or dirty host failure becomes `recovery_required` and retains exclusivity because restoring would destroy or misattribute work.
483
+ §worker-branch-batch-return **A child returns commits, never a dirty checkout.** SEND signals `200`, `499`, and an already-drained `202` are refused with 409 while the project repository is off the assigned branch or dirty. The model commits or deliberately discards its changes and concludes again. On terminal, the batch records the full result commit and whether it differs from the frozen base, restores the exact original ref and commit, and only then advances. A clean child failure is a completed batch item and does not suppress later siblings; an ambiguous or dirty host failure becomes `recovery_required` and retains exclusivity because restoring would destroy or misattribute work.
484
+
485
+ The active direct child's `Git Status` names its assigned branch and states the commit-and-clean return condition. No ordinary worker receives ambient commit or authorship policy; commit identity remains host-owned and outside model teaching. {§packet-git-status}
468
486
 
469
- §worker-branch-batch-receipt **The parent reconciles; the engine does not merge.** The ordinary child deliverable remains the model's exact SEND body. Its pushed termination delta and pull-side `READ(worker://child)` append a bounded branch receipt: branch, item outcome, and the abbreviated result commit (`PLURNK_SERVICE_BRANCH_RECEIPT_REVISION_CHARS`; the database retains the full id). Branch refs remain after the batch. The parent chooses inspection, cherry-pick, merge, rejection, or deletion with ordinary Git tools.
487
+ §worker-branch-batch-receipt **The parent reconciles; the engine does not merge.** The ordinary child deliverable remains the model's exact SEND result. Its pushed termination delta and pull-side `## READ0 (worker://child)` append a bounded branch receipt to the presented body without changing that result: branch, item outcome, and the abbreviated result commit (`PLURNK_SERVICE_BRANCH_RECEIPT_REVISION_CHARS`; the database retains the full id). Branch refs remain after the batch. The parent chooses inspection, cherry-pick, merge, rejection, or deletion with ordinary Git tools.
470
488
 
471
489
  §worker-branch-batch-recovery **Recovery follows durable ownership.** `branch_batches`, their ordered items, the project-repository snapshot, and result tips are schema state, not process memory. Generic boot recovery never starts their queued loops. A crash before sealing fails the unstarted batch. A queued partial preflight is rolled back only when every created ref still equals its frozen base, then retried. A running child is never replayed: its loop settles under the ordinary owner-loss rule; if the checkout is clean and either on the assigned branch or the exact original position, the committed tip is retained, the original restored, that item marked interrupted, and queued siblings continue. Any mismatch becomes `recovery_required` and keeps the workspace stopped for operator correction.
472
490
 
473
491
  The remaining worker surfaces are:
474
492
 
475
- - **Entries (storage)** — entry addressing rides the authority carving above ({§worker-authority-carving}): `worker:///` the commons, `worker://~/` the own space, a name an ancestry-gated read ({§worker-read-scope}), writes own-space-and-commons only ({§worker-write-scoping}). An entry-path `KILL` deletes under the same write-scoping (200; 404 absent; 403 named) — distinct from the path-ABSENT `KILL(worker://<name>)` which terminates the worker ({§worker-scheme-terminate}); the discriminator is the entry path, never the op. A worker's own space is catalogued in ITS perspective alone (`FIND(worker://~/*)`, foisted at turn 0 even when empty); isolation is the owner column, structural.
476
- - §worker-scheme-terminate **Terminate** — `KILL(worker://<name>)` aborts a named worker and `KILL(worker://~)` aborts the caller: every unresolved loop in that worker's subtree closes 499 and every subscription in the subtree tears down; a literal name with no worker is 404. Cancellation is structured: descendants cannot detach implicitly. The override to the fire-and-forget default is not a parent-power — whoever holds the address may end it; a worker left alone simply ends at its own `SEND[200]`.
493
+ - **Entries (storage)** — entry addressing rides the authority carving above ({§worker-authority-carving}): `worker:///` the commons, `worker://~/` the own space, a name an ancestry-gated read ({§worker-read-scope}), writes own-space-and-commons only ({§worker-write-scoping}). An entry-path `KILL` deletes under the same write-scoping (200; 404 absent; 403 named) — distinct from the path-absent `## KILL0 (worker://<name>)` which terminates the worker ({§worker-scheme-terminate}); the discriminator is the entry path, never the op. A worker's own space is catalogued in its perspective alone (`## FIND0 [+init] (worker://~/*)`, foisted at turn 0 even when empty); isolation is the owner column, structural.
494
+ - §worker-scheme-terminate **Terminate** — `## KILL0 (worker://<name>)` aborts a named worker and `## KILL0 (worker://~)` aborts the caller: every unresolved loop in that worker's subtree closes 499 and every subscription in the subtree tears down; a literal name with no worker is 404. Cancellation is structured: descendants cannot detach implicitly. The override to the fire-and-forget default is not a parent-power — whoever holds the address may end it; a worker left alone simply ends at its own SEND signal `200`.
477
495
  - §worker-scheme-cap **Cap** — `PLURNK_SERVICE_WORKSPACE_WORKERS_MAX_ACTIVE` ceilings the *concurrent* active workers per workspace (a worker with a non-terminal loop); a spawn or fork past it fails hard (508 — no queue, no retry), irc exempt; `-1` disables it. The fork-bomb brake, sized for workspaces that live for months.
478
496
  - §worker-scheme-collect **Collect** — a worker's loop reaching a terminal status
479
497
  surfaces to its sisters as an ambient delta ({§env-delta}): a `SEND` from
480
- `worker://<name>` carrying the loop's deliverable the `SEND[200]` body, or
481
- for an abandonment the reason. A **2xx deliverable is born OPEN** (its body
498
+ `worker://<name>` carrying the loop's exact terminal operation result. A
499
+ **2xx deliverable is born OPEN** (its body
482
500
  materialized into the parent's packet, not hidden behind a fold): a child's
483
501
  success must reach the parent open and awakening, never a bodyless row. An
484
- abandonment (non-2xx) surfaces folded. Every death-path is stamped uniformly,
502
+ non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly,
485
503
  so no termination is silent; collection is the shared world moving, never a
486
504
  verb. The **pull** side mirrors the push: a path-absent
487
- `READ(worker://<name>)` collects the same deliverable on demand the latest
488
- loop's terminal message (the result, or the abandonment reason) for a
505
+ `## READ0 (worker://<name>)` collects that same result on demand for a
489
506
  concluded worker; a worker **still running** has not delivered, so the READ
490
- returns **425** (Too Early) and the turn's bare `SEND[102]` **becomes a
507
+ returns **425** (Too Early) and the turn's bare SEND signal `102` **becomes a
491
508
  parked loop (202) on the join** ({§join-blocking-collect}) until the worker
492
509
  delivers — the engine holds the join, the model never drives a park. A
493
510
  missing name is 404. The model therefore reads the worker itself for its
@@ -505,7 +522,7 @@ The remaining worker surfaces are:
505
522
 
506
523
  ### §worker-loop-lifecycle Worker and loop lifecycle: drain, reap, and passive wake
507
524
 
508
- - §join-blocking-collect **A `READ` on a running child is a blocking join, not a poll.** A path-absent `READ(worker://<running-child>)` returns **425** (Too Early) and records a live obligation on the loop. The turn's bare `SEND[102]` is converted into an indefinite parked loop (202) instead of asking the model to poll or drive the scheduler. When the child reaches any terminal status, the same loop resumes with the result in its log. Children are bounded by their own turn and strike limits, terminal failure also wakes the parent, and the owed-wake path covers completion before the parent parks. Any `SEND` clears the per-turn arm; `SEND[200]` with a live child remains a premature-termination error. A `<seconds>` timeout-poll is the explicit polling alternative.
525
+ - §join-blocking-collect **A `READ` on a running child is a blocking join, not a poll.** A path-absent `## READ0 (worker://<running-child>)` returns **425** (Too Early) and records a live obligation on the loop. The turn's bare SEND signal `102` is converted into an indefinite parked loop (202) instead of asking the model to poll or drive the scheduler. When the child reaches any terminal status, the same loop resumes with the result in its log. Children are bounded by their own turn and strike limits, terminal failure also wakes the parent, and the owed-wake path covers completion before the parent parks. Any `SEND` clears the per-turn arm; SEND signal `200` with a live child remains a premature-termination error. A `<seconds>` timeout-poll is the explicit polling alternative.
509
526
 
510
527
  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.
511
528
 
@@ -526,8 +543,8 @@ stateDiagram-v2
526
543
  §stream-catalog-lifecycle Streams are independently durable subscriptions owned by a worker. Payload and
527
544
  lifecycle are orthogonal: zero bytes is a valid payload for both success and
528
545
  failure, while the closed subscription and its status are the terminal fact.
529
- Every stream entry exposes that durable state in catalog rows as
530
- `stream: { state, ... }`: active streams carry `seconds`; terminal streams carry
546
+ Every stream entry exposes that durable state on its catalog group's default
547
+ channel (`[0].stream: { state, ... }`): active streams carry `seconds`; terminal streams carry
531
548
  their exact `status` and derive `closed` (status below 400), `killed` (499), or
532
549
  `failed` (other failure status). An entry with no subscription has no `stream`
533
550
  member. This is historical state, not merely a live-process hint.
@@ -546,7 +563,7 @@ stateDiagram-v2
546
563
  Observed --> [*]
547
564
  ```
548
565
 
549
- | §worker-lifecycle-subscription-matrix Subscription state at `SEND[202]` | Terminal observation already in a packet | Result |
566
+ | §worker-lifecycle-subscription-matrix Subscription state at SEND signal `202` | Terminal observation already in a packet | Result |
550
567
  |-------------------------------------------------------------------------|---:|---|
551
568
  | open | no | park; polling or closure may wake it |
552
569
  | closed, any status, empty or non-empty | no | continue directly to the observation turn |
@@ -573,9 +590,9 @@ sequenceDiagram
573
590
  participant C as Child loop
574
591
  participant S as Child stream
575
592
  P->>C: WORK or FORK
576
- P->>P: SEND[202] parks on live child
593
+ P->>P: SEND 202 parks on live child
577
594
  C->>S: EXEC opens subscription
578
- C->>C: SEND[202] parks on live stream
595
+ C->>C: SEND 202 parks on live stream
579
596
  loop backoff, fixed cadence, or explicit arrival
580
597
  S-->>C: optional progress observation
581
598
  C->>C: continue or park
@@ -596,15 +613,17 @@ sequenceDiagram
596
613
  | cancelled or failed terminal | no | same wake/delivery path as success; outcome remains non-2xx |
597
614
 
598
615
  A stream's close status and a loop's terminal status are separate layers. A
599
- stream may close 4xx/5xx and wake its worker to recover. Model `SEND[4xx/5xx]`
600
- reports a failed action and continues; `SEND[200]` concludes successfully and
601
- `SEND[499]` explicitly abandons the worker. Only a concluded loop crosses the
616
+ stream may close 4xx/5xx and wake its worker to recover. Model SEND signals
617
+ `4xx/5xx` report a failed action and continue; signal `200` concludes successfully and
618
+ signal `499` explicitly abandons the worker. Only a concluded loop crosses the
602
619
  parent edge as the child's result.
603
620
 
604
621
  §worker-lifecycle-terminal-result **Terminal truth is a result, not a lifecycle code.** `loops.terminal_result`
605
622
  stores the exact universal operation result. A failure therefore retains its
606
623
  RFC 9457 Problem Details and exact status through persistence, restart,
607
- parent collection, and `loop/terminated`. The older constrained `loops.status`
624
+ parent collection, and `loop/terminated`; successful terminal SEND content and
625
+ mimetype remain in the same result. Cancellation markers and branch receipts
626
+ are derived presentation, never a second stored outcome. The constrained `loops.status`
608
627
  column remains only the scheduler's compact lifecycle projection: known
609
628
  terminal classes remain themselves, other 2xx/3xx statuses project to `200`,
610
629
  and other 4xx/5xx statuses project to `500`; exact `202` is forbidden because
@@ -632,15 +651,16 @@ observe their terminal results. No effect is replayed across an unknown
632
651
  boundary.
633
652
 
634
653
  - §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.
635
- - §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel`, worker `KILL`, shutdown, and a worker's `SEND[499]` 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. 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` the executor's SIGHUP default, `KILL[9]` SIGKILL).
654
+ - §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel`, worker `KILL`, shutdown, and a worker's SEND signal `499` 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. 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 `## KILL0 [code]` on one live stream instead delivers exactly that signal once (bare KILL uses the executor's SIGHUP default; `## KILL0 [9]` uses SIGKILL).
636
655
  - §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.
637
656
  - §worker-lifecycle-no-resurrection **A cancelled worker is not resurrected by its own torn-down work.** A stream conclusion delivered to a cancelled, idle worker starts no fresh drain: an aborted (499) conclusion is skipped, and a straggler that concluded cleanly surfaces its deliverable as an environment delta ({§env-delta}), never a revived loop. The cancel was deliberate; only an explicit `runLoop` request resumes the worker.
638
657
  - §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** When a backgrounded stream concludes, the daemon routes it through the same inject seam as any loop source ({§actor-boundary-passive-wake}): an active worker folds the conclusion into its next turn; a worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) **awakens that loop in place** — the blocked loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. The result is never lost: a blocked loop sleeps rather than ending, and the stream's status-transition is the arrival ({§actor-boundary-passive-wake}) that wakes it; on resume it reads the concluded stream's own state, not a synthetic prompt.
639
- - §worker-lifecycle-child-wake **A child worker concluding wakes a parent blocked on it — the topology join.** `worker://` spawn/fork records `parent_worker_id` ({§lifecycle-terms}). When a worker's drain exits having **concluded** — no `202`-blocked loop, no open stream — the daemon resumes its parent **in place** if the parent is blocked on the join (`#onDrainExit` → the shared `#wakeParkedWorker`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and blocks (`SEND[202]`) is woken the moment its child finishes; on resume it reads the child's deliverable from the {§worker-scheme-collect} delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself blocked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child workers are the same kind of "live thing a worker holds," driving premature-terminate ({§send-premature-terminate}), the wake edge, and the collect delta identically. A worker conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its block commits), `#wakeParkedWorker` finds it not-yet-slept and records an **owed wake**, which the drain honors when the parent blocks — so a wait awaiting workers **always returns**, never dead-blocks on a conclude-before-block race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a wait open.)
640
- - §worker-lifecycle-idle-is-concluded **An idle worker concludes; it does not park.** A loop is idle only when it has neither live obligations nor completed results awaiting their first packet. A live child or stream blocks a `SEND[202]` join; a completed stream, child result, or same-turn retrieval continues directly to the next packet where it is observed. Only after those sets are drained does `SEND[202]` resolve like `SEND[200]`. There is no held-open idle loop and no `loop/quiesced` soft signal. A concluded worker is durable working history and an addressed arrival reawakens it as a new loop.
658
+ - §worker-lifecycle-child-wake **A child worker concluding wakes a parent blocked on it — the topology join.** `worker://` spawn/fork records `parent_worker_id` ({§lifecycle-terms}). When a worker's drain exits having **concluded** — no `202`-blocked loop, no open stream — the daemon resumes its parent **in place** if the parent is blocked on the join (`#onDrainExit` → the shared `#wakeParkedWorker`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and blocks with SEND signal `202` is woken the moment its child finishes; on resume it reads the child's deliverable from the {§worker-scheme-collect} delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself blocked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child workers are the same kind of "live thing a worker holds," driving premature-terminate ({§send-premature-terminate}), the wake edge, and the collect delta identically. A worker conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its block commits), `#wakeParkedWorker` finds it not-yet-slept and records an **owed wake**, which the drain honors when the parent blocks — so a wait awaiting workers **always returns**, never dead-blocks on a conclude-before-block race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a wait open.)
659
+ - §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 terminal SEND; separately, a stream or direct-child conclusion persists and publishes immediately but holds the parked worker's single `202→100` requeue 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 every conclusion that lands within it into one requeue. 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.
660
+ - §worker-lifecycle-idle-is-concluded **An idle worker concludes; it does not park.** A loop is idle only when it has neither live obligations nor completed results awaiting their first packet. A live child or stream blocks a SEND signal `202` join; a completed stream, child result, or same-turn retrieval continues directly to the next packet where it is observed. Only after those sets are drained does signal `202` resolve like signal `200`. There is no held-open idle loop and no `loop/quiesced` soft signal. A concluded worker is durable working history and an addressed arrival reawakens it as a new loop.
641
661
  - §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.
642
662
  - §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.
643
- - §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 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}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation survives only while a live child obligation remains; after reconciliation, an unblocked park requeues `202→100` and resumes in place. 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.
663
+ - §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 beneath that loop 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}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation survives only while a live child obligation remains; after reconciliation, an unblocked park requeues `202→100` and resumes in place. 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.
644
664
 
645
665
  ---
646
666
 
@@ -650,13 +670,12 @@ Author-facing contract: [`@plurnk/plurnk-providers`](../plurnk-providers/SPEC.md
650
670
 
651
671
  ### §provider-surface Consumption surface
652
672
 
653
- Three entry points:
673
+ Two current entry points:
654
674
 
655
- - §provider-surface-generate `provider.generate(args)` — once per provider attempt. Core supplies the complete messages, worker/turn coordinates, generation envelope, optional local grammar, and first-party metadata. A successful `ProviderResponse` reaches emission admission; a `ProviderError.attempt` is failed evidence under {§provider-interrupted-attempt}. Core persists normalized call metadata and forensic response fields and relays encrypted-reasoning items only from an admitted response ({§encrypted-reasoning-carrier}).
656
- - §provider-surface-prompt-measurement `provider.countPromptTokens(messages, signal)` — cancellable measurement of the complete provider request with `exact`, `upper_bound`, or `estimate` provenance. It is used only for provider-physical recovery admission ({§tokenomics-physical-admission}); model-facing stored and rendered weights use the provider-agnostic ruler.
657
- - §provider-surface-calculate-cost `provider.calculateCost(usage)` — once per persisted provider attempt carrying usage; estimated USD. Engine aggregates every attempt into `turns.usage_cost_usd`; triggers cascade to `workers.cost_usd` / `workspaces.cost_usd`.
675
+ - §provider-surface-generate `provider.generate(args)` — once per logical model call. An emission attempt supplies the complete packet messages, worker/turn coordinates, generation envelope, optional local grammar, first-party metadata, and `callKind: "emission"`. A BARE inference supplies only one user message containing its body plus non-prompt call identity and accounting metadata, including `callKind: "bare"` ({§bare-inference} {§provider-call-kind}). Both receive a durable physical-request observer; provider-owned retry and failover may issue several ordered requests beneath either call. A successful `ProviderResponse` reaches its call-specific consumer; a `ProviderError.attempt` remains failed response evidence under {§provider-interrupted-attempt}. Core persists normalized response evidence separately from physical accounting and relays encrypted reasoning only from an admitted emission ({§encrypted-reasoning-carrier}).
676
+ - §provider-surface-prompt-measurement `provider.countPromptTokens(messages, signal)` — cancellable measurement of the complete provider request with `exact`, `upper_bound`, or `estimate` provenance. It is used only for hard context-envelope admission ({§tokenomics-context-envelope-admission}); model-facing stored and rendered weights use the provider-agnostic ruler.
658
677
 
659
- §provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow` (physical token total, or `null` when unknown) and the optional reasoning/completion reserves define the natural prompt partition and physical admission check ({§tokenomics}); `model` identifies persisted turn/provider evidence. Local GBNF boot verification also consumes `constrainsOutput` ({§grammar-enforcement-verified-at-boot}).
678
+ §provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow` (the effective total context envelope, or `null` when unknown) and the optional reasoning/completion reserves define the natural prompt partition and hard admission check ({§tokenomics}); `model` identifies persisted turn/provider evidence. Local GBNF boot verification also consumes `constrainsOutput` ({§grammar-enforcement-verified-at-boot}).
660
679
 
661
680
  §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}).
662
681
 
@@ -665,30 +684,37 @@ Three entry points:
665
684
  - `messages` is a complete prompt (the section list, pre-assembled into the system + user messages). Provider does not reorder.
666
685
  - §provider-guarantees-signal-wired `signal` is wired to the worker's AbortController.
667
686
  - §provider-guarantees-serial-attempts Emission attempts for one engine turn are serial. They reuse the exact messages, coordinates, generation limits, and strike state; two attempts for that turn never overlap.
687
+ - BARE calls admitted by one turn launch as one parallel batch; each call retains independent observer and failure state, and the engine awaits the complete batch before committing results in authored order ({§bare-inference}).
688
+ - §provider-guarantees-request-observer Immediately before each physical provider I/O, the provider opens its provider/model identity through `observeRequest` and settles the returned handle exactly once as response or error. Core durably records that occurrence before I/O and rejects a returned response or `ProviderError` whose ordered accounting differs from the observed records. Persistence failure is an internal contract failure, never optional telemetry.
668
689
  - §provider-guarantees-assistantraw-opaque `assistantRaw` is opaque to the engine (forensics-only).
669
- - `countPromptTokens` receives the exact `PacketWire` messages later supplied to `generate`. The engine calls it only for an over-policy recovery candidate; it may perform provider I/O and receives the loop cancellation signal.
690
+ - `countPromptTokens` receives the exact `PacketWire` messages later supplied to `generate`. The engine calls it only when negative ruler pressure requires hard context-envelope admission; it may perform provider I/O and receives the loop cancellation signal.
670
691
 
671
692
  ### §emission-admission Provider emission admission
672
693
 
673
694
  A completed provider exchange is an **emission attempt**, not necessarily an engine turn. The provider transports and observes the model's bytes; ANTLR is the admission authority only after provider completion. Admission asks whether the exchange has a trustworthy frame: its first parsed operation is PLAN, its last parsed operation is a terminal SEND, every hard parse error is bounded between those anchors, and no `unparsedTail` exists. Missing anchors, an error outside the frame, or a boundary-destroying tail rejects the entire exchange regardless of `finishReason`; no recovered prefix dispatches. Parser warnings remain admissible. `finish=length` is forensic evidence of likely truncation, not an independent rejection rule. A provider-declared resource interruption never reaches admission, even when its partial bytes form a complete-looking frame ({§provider-interrupted-attempt}).
674
695
 
675
- Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch, enter the Log, become model history, mint a model-facing error, or reach the engine strike rail. Every response-bearing attempt remains durable in `turn_attempts` with its raw response, parser errors, usage, and cost. The accepted exchange alone completes `turns.packet`; all billed attempts aggregate into the turn's usage while the context gauge reads the latest attempt's prompt usage. Digest exposes rejected evidence as `packetNNN.attemptNNN.rejected.*`.
696
+ Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch or reach the engine strike rail. Before each `generate`, Core opens one durable logical `model_calls` row and its emission-specific `turn_attempts` admission row. Beneath the model call, every provider observer invocation opens one cardinal `provider_requests` occurrence immediately before physical I/O and settles it as response or error. Adapter retries and capacity failover append requests in issue order; a response-less failure therefore remains an accounted occurrence rather than disappearing. Normalized response evidence is durable before parser classification and does not duplicate the separately owned accounting. The accepted exchange alone completes `turns.packet`; every physical request remains in turn and loop accounting, while the context gauge reads the latest settled emission request on the latest turn. Digest exposes rejected response evidence as `packetNNN.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
676
697
 
677
- An admitted frame may contain bounded malformed statements. Parsed operations still dispatch; each malformed statement becomes one durable model-origin `error` row with the parser's exact diagnostic under {§parse-diagnostics} and status 400. These failures are committed before the terminal disposition, participate in the ordinary strike rail, and prevent SEND[200] or an already-drained SEND[202] from concluding before the model sees them in the next packet. This is operation recovery, not provider resampling.
698
+ The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED model item under {§model-entry-log-curation} and carries one transient `invalid_emission` Notice whose complete message is: `Your previous response contained an unrecoverable syntax error. No operations were performed. Try again.` No parser diagnostic, attempt count, or rail state becomes 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 the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
699
+
700
+ An admitted frame may contain bounded malformed statements. Parsed operations still dispatch; each malformed statement becomes one durable model-origin `error` row with the parser's exact diagnostic under {§parse-diagnostics} and status 400. These failures are committed before the terminal disposition, participate in the ordinary strike rail, and prevent SEND signal `200` or an already-drained signal `202` from concluding before the model sees them in the next packet. This is operation recovery, not provider resampling.
678
701
  The Problem recovery states that only the failed operation needs correction
679
702
  because its parsed siblings were retained; the parser-owned detail states the
680
703
  specific syntax rule.
681
704
 
682
- §invalid-emission-attempts Exhausting the emission-attempt budget terminates
683
- the loop at 500 without spending an engine strike.
705
+ §invalid-emission-attempts Exhausting the emission-attempt budget opens the
706
+ single informed recovery turn above. Consecutive exhaustion of that turn
707
+ terminates the loop at 500 without spending an engine strike.
684
708
 
685
709
  §turn-never-blank An admitted turn whose operation fails — during parsing or
686
710
  dispatch — is categorically different: its failed operation row enters
687
711
  model-visible history and the next engine turn may recover. A `ProviderError`
688
- means no completed exchange exists (auth, network beyond provider retries,
689
- rate limit, or provider-declared interruption). When the error carries
690
- interrupted attempt evidence, core stores it unaccepted with its usage and cost;
691
- the failed turn still stores the exact request and never fabricates an assistant.
712
+ means no exchange was admitted (auth, exhausted transport retries, rate limit,
713
+ or provider-declared interruption). Core settles and retains every physical
714
+ request's known or unknown {§provider-request-accounting}; when the error carries
715
+ interrupted response evidence, Core stores it unaccepted without duplicating its
716
+ accounting. The failed turn still stores the exact request and never fabricates
717
+ an assistant or a zero-valued observation.
692
718
 
693
719
  ### §attribution Plugin-authored attribution folksonomy
694
720
 
@@ -701,10 +727,10 @@ shared contract {§plugin-attribution}:
701
727
 
702
728
  | Stage | Contract |
703
729
  | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
704
- | Collection | Immediately before each provider emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. Static declarations and runtime hook results are additive. |
730
+ | Collection | Immediately before each emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. A BARE call pulls only its selected provider source because it admits no other plugin capability. |
705
731
  | Composition | Core flattens, deduplicates, and sorts the tags. The resulting non-empty array rides `generate({ attributions })`; an empty set omits that provider field. |
706
732
  | Meaning | Core neither verifies nor infers contribution. Tags are plugin-authored folksonomy for telemetry, optimization, attribution, or downstream rules. The `@plurnk/` reservation is the only namespace policy ({§plugin-attribution}). |
707
- | Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Each response-bearing `turn_attempts` row carries its attempt's exact set, so rejected attempts remain distinguishable and a response-less failure is still represented by the request packet. |
733
+ | Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Every pre-I/O `model_calls` row carries that call's exact set, including response-less failures. |
708
734
  | Derived reporting | Turn, loop, digest, and client views project the recorded sets. `loop/terminated.attributions` is their deduplicated sorted union and remains separate from provider usage and charge evidence. |
709
735
 
710
736
  Runtime hooks are synchronous and receive only the attempt coordinates. A hook
@@ -729,16 +755,20 @@ plugin discovery is the last protocol-extension seam.
729
755
  The ANTLR grammar always defines and validates the PLURNK language. Separately,
730
756
  an operator may configure `PLURNK_PROVIDERS_GBNF_<alias>` for a local
731
757
  llama-server. The provider must advertise GBNF transport and satisfy a forcing
732
- probe whose pre-projection sentence is one reasoning enclosure followed by the
733
- `PLURNK-RAILS-LIVE` sentinel, or boot fails. The setting is resolved
758
+ probe whose sampled sentence and pre-projection response match the selected
759
+ rail's template boundary followed by the `PLURNK-RAILS-LIVE` sentinel, or boot
760
+ fails. The setting is resolved
734
761
  per alias and is unset by default. Configuring it on a cloud or endpoint-managed
735
762
  provider is an error, not a request for best-effort filtering.
763
+ Alias-scoped `PLURNK_PROVIDERS_GBNF_DEBUG` deliberately withholds transport, so
764
+ boot skips the enforcement probe while real requests retain the configured rail
765
+ for local syntax validation and the engine's withheld-rail verdict.
736
766
  Runtime injection uses the provider's registered alias, falling back only to
737
767
  the process's active alias. Suffixed rail settings with neither identity fail
738
768
  instead of guessing. A configured package variant or explicit path that cannot
739
769
  be loaded also fails; it never silently becomes unconstrained.
740
770
 
741
- §gbnf-requires-reasoning The shipped PLURNK rail requires reasoning. The same alias-scoped configuration
771
+ §gbnf-requires-reasoning Both shipped PLURNK rails require reasoning. The same alias-scoped configuration
742
772
  must resolve reasoning to `adaptive` or `on`; `off` with GBNF is rejected before
743
773
  the probe or any model generation. Reasoning-off remains valid when no GBNF rail
744
774
  is configured.
@@ -746,7 +776,8 @@ is configured.
746
776
  §rail-truth-engine-verdict **Local constraint truth is independently observed.**
747
777
  For a configured local GBNF, the provider returns the pre-projection sentence as
748
778
  `grammarEvidence` under `plurnk-providers` {§gbnf-response-observation}. The engine
749
- requires that evidence, independently validates `grammarEvidence.input`, and
779
+ requires that evidence, independently validates `grammarEvidence.input` with the
780
+ artifact's declared response root, and
750
781
  stamps `railsAttached: "client"` when transported or `"withheld"` in debug mode
751
782
  plus `railsVerdict`; it never validates projected
752
783
  `assistant.content` as though the required reasoning enclosure were still
@@ -847,7 +878,7 @@ Every fact names the canonical key, never the host root or an echo of the
847
878
  model's spelling. These classes let a caller distinguish a wrong address, an
848
879
  invalid range, read-only authority, and occupied hidden state without guessing.
849
880
 
850
- §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, orphan-freedom (channels/tags without parents), the closed admission set (a file row's grantor is git or a client act — or the create-accepted transient NULL the next reconcile stamps), and sig-coherence. It 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.
881
+ §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 (a file row's grantor is git or a client act — or the create-accepted transient NULL the next reconcile stamps), and sig-coherence. It 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.
851
882
 
852
883
  ### §scheme-manifest Manifest
853
884
 
@@ -878,9 +909,11 @@ Registration precedes loop affinity:
878
909
  | Registered but inactive under flag | The flag gate returns `403 scheme-unavailable`. |
879
910
  | Registered and active | Dispatch continues to the operation owner. |
880
911
 
881
- - §op-mode-phases **A continuing turn executes in MODE phases.** A model turn describes intended effects and requested observations; it is not an imperative program whose later statements can consume invisible same-turn results. The engine therefore performs four stable phases: **Mutate** (`EDIT`, `COPY`, `MOVE`, `KILL`, `FOLD`), **Observe** (`FIND`, `READ`, `OPEN`), **Do** (all remaining non-terminal actions, including `EXEC`, `WORK`, `FORK`, and directed `SEND`), then **End** (the terminal `SEND`). `PLAN` remains the turn anchor and is recorded before those phases. Authored order is preserved within each phase. A result still lands in the next packet; phasing makes that result describe settled state instead of an accidental intermediate state.
912
+ - §op-mode-phases **A continuing turn executes in MODE phases.** A model turn describes intended effects and requested observations; it is not an imperative program whose later statements can consume invisible same-turn results. The engine therefore performs four stable phases: **Mutate** (`EDIT`, `COPY`, `MOVE`, `KILL`, `FOLD`), **Observe** (`FIND`, `READ`, `OPEN`, `BARE`), **Do** (all remaining non-terminal actions, including `EXEC`, `WORK`, `FORK`, and directed `SEND`), then **End** (the terminal `SEND`). `PLAN` remains the turn anchor and is recorded before those phases. Authored order is preserved within each phase. A result still lands in the next packet; phasing makes that result describe settled state instead of an accidental intermediate state.
913
+
914
+ §bare-inference **BARE is isolated, synchronous retrieval over the durable child-provider policy.** Its body is the complete prompt and becomes the sole user message; Core supplies no PLURNK system packet, log context, tools, GBNF, parser, target, worker, or persistent child state. The selected provider is exactly the loop's WORK/FORK child provider, falling back to the parent provider when the durable policy is inherit. All BARE statements in one admitted turn receive logical model-call identities in authored order and launch concurrently under the loop cancellation signal. Core awaits the batch, isolates a provider failure to that operation, then records results and notifications in authored order regardless of completion order. Accounting or persistence failure is internal and fails hard. Each response is unseen retrieval work: the canonical disposition is `SEND[102]`, and same-turn `SEND[200]` is refused until the next packet presents it.
882
915
 
883
- - §op-synchronous **Decisive operations settle before the next scheduled operation.** The dispatcher `await`s every decisive operation. Work remains in flight only when the operation's contract deliberately creates concurrency: `FORK`, `WORK`, stream-producing `EXEC`, and a streaming `READ` after its scheme-specific acquisition boundary. Such a READ first establishes its durable subscription, returns `102`, and then retains only its `StreamSubscription`; a later scheduled operation may address that live owner. MODE changes scheduling, not completion semantics. This is why a same-turn `KILL + SEND[200]` concludes ({§send-premature-terminate}): `KILL` synchronously flips the worker's live loops terminal (`engine_terminate_worker_live_loops`) before the End phase judges the pending set, while the physical scope reap rides `cancelWorker` asynchronously and invisibly.
916
+ - §op-synchronous **Decisive operations settle before the next scheduled operation.** The dispatcher `await`s every decisive operation. Work remains in flight only when the operation's contract deliberately creates concurrency: `FORK`, `WORK`, stream-producing `EXEC`, and a streaming `READ` after its scheme-specific acquisition boundary. Such a READ first establishes its durable subscription, returns `102`, and then retains only its `StreamSubscription`; a later scheduled operation may address that live owner. MODE changes scheduling, not completion semantics. This is why a same-turn KILL followed by SEND signal `200` concludes ({§send-premature-terminate}): KILL synchronously flips the worker's live loops terminal (`engine_terminate_worker_live_loops`) before the End phase judges the pending set, while the physical scope reap rides `cancelWorker` asynchronously and invisibly.
884
917
 
885
918
  - §edit-batch **Same-resource EDITs are one mutation.** Every EDIT targeting the same canonical resource and channel in one turn applies to the resource's one pre-turn snapshot. The scheme validates the complete batch before writing, applies disjoint replacements from the highest original coordinate downward, and commits one resulting revision atomically; reversing the statements cannot change that revision. A failing statement rejects that resource batch without a partial write; independent resource batches remain independent. Whole-resource replacement or creation cannot coexist with another EDIT in the same batch, selected regions may not overlap, and a zero-length insertion may occur at most once at each boundary. Prepend (`<0>`), append (`<-1>`), and exact equal-endpoint insertions compose with non-overlapping replacements. Proposal-gated schemes expose one proposal for the resource batch and accept all or none. The public scheme contract is batch-shaped: a scheme must never emulate this guarantee by applying individual EDITs sequentially.
886
919
 
@@ -914,14 +947,14 @@ Details state `destinationWritten: true` and identify the destination.
914
947
 
915
948
  Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
916
949
 
917
- - `SEND[200](path)` — write body into resource (WS message, exec stdin).
918
- - `SEND[499](path)` — cancel active subscription ({§stream}).
950
+ - `## SEND0 [200] (path)` — write body into resource (WS message, exec stdin).
951
+ - `## SEND0 [499] (path)` — cancel active subscription ({§stream}).
919
952
 
920
- - §log-uniform-query **Log speaks the universal query contract** — `FIND(log://…)` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~semantic` and `@graph` use the same persistent derivation artifacts and candidate rankers as entries. Results are catalog-shaped items keyed `log:///loop/turn/seq/OP`, and matcher READ retargets per-row READs exactly as entry schemes do. A tag signal filters candidates by the model's own region tags ({§log-region-tagging}). Log remains an event stream in storage; uniformity begins at its readable projection and search attachment, not by forcing logs into the entries table.
921
- - §find-source-agnostic **The content matcher is source-agnostic** — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND/READ with every content dialect works uniformly across schemes BY CONSTRUCTION `EntryFind` and `Log.find` run the ONE shared primitive rather than re-implementing per scheme. This is the query-layer half of the log-uniformity decision (Q3, Option B): log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
922
- - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{path?,region?}`. `path` preserves a structural locator. `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Multiple findings on one resource remain one FIND/READ result; exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. The engine never fabricates a region or guesses which surgical READ the model wants.
953
+ - §log-uniform-query **Log speaks the universal query contract** — `## FIND0 (log://…)` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~semantic` and `@graph` use the same persistent derivation artifacts and candidate rankers as entries. Broad results are one-channel catalog groups whose `[0].path` is `log:///loop/turn/seq/OP`; exact matcher results are flat locations ({§find-result-projection}). A FIND signal classifies the FIND result row and never changes this candidate set ({§log-item-tags}). Log remains the core event ledger rather than duplicating rows into `entries`; its core-private storage adapter supplies one complete channel representation to the same READ projector. That adapter is not a plugin seam and grants no protocol scheme an alternate READ path.
954
+ - §find-source-agnostic **The content matcher is source-agnostic** — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND works uniformly across schemes by construction: `EntryFind` and `Log.find` run the one shared primitive rather than re-implementing it per scheme. Log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
955
+ - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{locator?,region?}`. `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.
923
956
 
924
- `SEND[410](path[#fragment])` also deletes the target entry/channel — an implemented side-effect, NOT taught to the model and with no live/demo surface. The model-facing delete idiom is KILL ({§move}).
957
+ `## SEND0 [410] (path[#fragment])` also deletes the target entry/channel — an implemented side-effect, NOT taught to the model and with no live/demo surface. The model-facing delete idiom is KILL ({§move}).
925
958
 
926
959
  §send-dispatch-entry-schemes-501-on-non-410 Other status codes return 501 from entry-bearing schemes by default.
927
960
 
@@ -956,11 +989,25 @@ The optional engine-/daemon-populated capabilities (the notifiers, `injectWorker
956
989
  Engine → scheme guarantees:
957
990
 
958
991
  - `ctx` is fresh per call. No mutation across calls.
959
- - FIND or matcher READ on a `category: "data"` scheme with no custom `find()`
960
- invokes its optional `prepareFind()` and then the standard entry selection.
961
- Preparation owns discovery/materialization only; query semantics remain
962
- universal. The prepared write and the query resolve through one canonical
963
- entry identity, including every component owned by {§scheme-address}.
992
+ - §universal-read-composition **Exact READ has one composition.** Core resolves
993
+ canonical identity and owner once, gives a data scheme its optional
994
+ `prepareRepresentation({ target, pathname })` opportunity, reads the complete
995
+ canonical channels, selects the authored channel, applies binary and
996
+ text-coordinate rules, and finally composes that channel's durable producer
997
+ result. Preparation receives neither fragment nor `lineMarker`; finite work
998
+ returns `200`, while only a retained live representation may return `102`
999
+ ({§read-preparation}). No public handler can replace READ.
1000
+ - Exact FIND uses the same resolved identity and representation preparation
1001
+ before standard entry selection, then composes the exact default channel's
1002
+ durable producer result with the core-owned query projection. Broad FIND may invoke a custom `find()` for
1003
+ genuinely protocol-owned candidate enumeration, or `prepareFind()` followed
1004
+ by the standard catalog query. Acquisition never owns matcher, pagination,
1005
+ or result-unit semantics. Every prepared write and query preserves all
1006
+ identity components owned by {§scheme-address}.
1007
+ - COPY/MOVE source selection resolves and prepares that same canonical
1008
+ representation before selecting a channel. Its independent source scope
1009
+ remains raw transfer semantics—markerless means the complete channel rather
1010
+ than READ's preview—and is structurally unavailable to the producer.
964
1011
  - `ctx.writer` reflects the actual writer at this dispatch.
965
1012
  - §scheme-surface-writableby-403 `manifest.writableBy` is checked BEFORE invocation; engine returns 403 directly on exclusion.
966
1013
  - `ctx.signal` is wired to the worker's AbortController ({§provider-guarantees-signal-wired}).
@@ -1033,10 +1080,10 @@ plurnk-service is mimetype-illiterate. Engine hands channel content + mimetype l
1033
1080
 
1034
1081
  §mimetype-owned-lifecycle `Daemon` owns and disposes the `Mimetypes` instance
1035
1082
  it constructs. A constructor-injected instance remains caller-owned. Shutdown
1036
- quiesces model work, awaits derivation warming, then disposes the daemon-owned
1037
- instance exactly once; mimetype teardown failures retain their causes and join
1038
- the same aggregate as module and scheme shutdown failures. A pre-start or
1039
- repeated stop does not acquire or dispose resources.
1083
+ quiesces model work, cancels and settles active derivation warming, then
1084
+ disposes the daemon-owned instance exactly once; mimetype teardown failures
1085
+ retain their causes and join the same aggregate as module and scheme shutdown
1086
+ failures. A pre-start or repeated stop does not acquire or dispose resources.
1040
1087
 
1041
1088
  §mimetype-classification-consumption Every engine-owned binary decision uses
1042
1089
  the configured `Mimetypes.classify()` path. An installed handler declaration
@@ -1061,8 +1108,8 @@ discovery ({§mimetype-discovery}).
1061
1108
  projection is independent of packet budgeting. Core uses the stable
1062
1109
  model-independent ruler for stored/catalog weights and the model-facing budget
1063
1110
  ({§tokenomics-agnostic-ruler}). The provider's request-shaped measurement is
1064
- confined to provider-physical recovery admission
1065
- ({§tokenomics-physical-admission}).
1111
+ confined to hard context-envelope admission
1112
+ ({§tokenomics-context-envelope-admission}).
1066
1113
 
1067
1114
  §persistent-search-index **Persistent search index.** `SearchIndex.maintain` is the pre-model engine pass. Each searchable resource supplies an address and the exact readable body its READ exposes. Entries supply their default body; `LogBody` resolves each log row's canonical full body from its durable tx/rx envelope. Acquisition schemes project remote source material before storing that body; search never introduces a second hidden text projection. The readable body, mimetype, resolved text/binary classification, mimetype projection identity, embedder configuration, and applicable search exclusion form a content hash. Complete artifacts own FTS, vectors, symbol definitions, and references; resource rows hold only the attachment hash. Binary, empty, and excluded derivations do not invoke handler projections and therefore use one fixed no-projection identity.
1068
1115
 
@@ -1133,7 +1180,7 @@ A published default channel renders under the entry's ordinary fragmentless addr
1133
1180
 
1134
1181
  ### §no-visibility Entries carry no visibility
1135
1182
 
1136
- Every entry is uniformly listed in the catalog (`FIND(scheme:///**)`, {§packet}) and READable — entries have no per-worker open/folded state. Context curation is the model's, on the **log** (via OPEN/FOLD, {§open-fold}), never on entries.
1183
+ Every entry is uniformly listed in the catalog (`## FIND0 (scheme:///**)`, {§packet}) and READable — entries have no per-worker open/folded state. Context curation is the model's, on the **log** (via OPEN/FOLD, {§open-fold}), never on entries.
1137
1184
 
1138
1185
  ### §channel-mimetype Mimetype is a (scheme, channel) property — never a default
1139
1186
 
@@ -1167,14 +1214,7 @@ Op implications:
1167
1214
 
1168
1215
  Client-interface target parameters carry fragments inline (`{ target: "sh:///1/1/2#stderr" }`).
1169
1216
 
1170
- **Wire rendering: default channel is path-only.** Heredoc fence 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`.
1171
-
1172
- ```
1173
- <<notes.md:...:notes.md — file scheme (bare)
1174
- <<sh:///1/1/2:...:sh:///1/1/2 — exec output default (stdout)
1175
- <<sh:///1/1/2#stderr:...:sh:///1/1/2#stderr — non-default
1176
- <<log:///1/1/0:...:log:///1/1/0 — atomic log row
1177
- ```
1217
+ **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`.
1178
1218
 
1179
1219
  ### §channel-state Channel state — metadata, not gating
1180
1220
 
@@ -1195,56 +1235,151 @@ Model uses state to anticipate growth between turns. Clients use state for UI (s
1195
1235
 
1196
1236
  Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkStatement`. Engine dispatches by `op`; scheme implements per author contract ({§scheme}).
1197
1237
 
1238
+ ### §line-anchors Text line anchors
1239
+
1240
+ A scheme declaring `textEditScopes: true` with model write authority publishes
1241
+ the contracts-owned {§text-line-anchor-syntax}. For canonical model-facing
1242
+ resource identity `R`, one-based line ordinal `L`, configured non-negative
1243
+ neighbor count `C`, and ordered content array `W` containing that line and up to
1244
+ `C` complete lines on either side (all excluding separators), core hashes the
1245
+ JSON tuple `["plurnk-line-anchor-v1",R,L,C,W]` with SHA-256, interprets the
1246
+ digest as a big-endian integer modulo `62^5`, and encodes five fixed-width
1247
+ characters with alphabet `0-9A-Za-z`. The universal READ projector derives
1248
+ anchors from the complete canonical selected channel before applying the
1249
+ authored text slice; its durable result retains the canonical derivation
1250
+ identity and anchors aligned with returned lines. Packet rendering right-aligns
1251
+ `L` to the decimal width of the complete canonical selected channel's final
1252
+ addressable line and emits `@xxxxx L:<content>` with one or more ASCII spaces
1253
+ before `L`; a source line therefore retains the same prefix across projections
1254
+ of one revision.
1255
+ An explicit default-channel fragment and its fragmentless spelling share that
1256
+ identity; a selected non-default channel retains its canonical `#channel`.
1257
+
1258
+ For READ/LOOK and COPY/MOVE source or destination selection, core resolves every
1259
+ anchor against the addressed current complete content before applying the
1260
+ ordinary numeric text-coordinate contract. Exactly one current match lowers to
1261
+ its numeric line; zero or multiple matches return 409 `line-anchor-collision`,
1262
+ and an anchor in a column position returns 400. COPY/MOVE mutation owners retain
1263
+ the resolved endpoint neighborhoods as compare-and-swap preconditions. There is
1264
+ no revision sidecar or fuzzy relocation. A range authenticates both endpoint
1265
+ neighborhoods, so every line of a range up to `2C + 2` lines is covered; a
1266
+ longer range retains an unauthenticated interior gap. The shipped `C = 2`
1267
+ covers ranges through six lines.
1268
+
1198
1269
  ### §edit EDIT
1199
1270
 
1200
- AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker? }`.
1271
+ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker?: TextLineMarker }`.
1201
1272
 
1202
1273
  - Resolves target channel from fragment ({§channel-selection}); unknown channel → 400; undeclared in manifest → engine crash ({§channel-mimetype}).
1203
1274
  - §edit-null-clears Writes the body; `body: null` clears it.
1204
1275
  - §edit-status-201-200 Returns `{ status: 201, entryId }` for a new entry and
1205
1276
  `{ status: 200, entryId }` for a content update.
1206
- - §edit-noop-304 A write that changes nothing — identical content and no new tag — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's idempotence ({§open-fold}).
1207
- - §edit-tags-additive Tags from `signal[]` apply additively via `entry_tags` (scheme may vary).
1277
+ - §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's idempotence ({§open-fold}). The operation's log classification remains independent ({§log-item-tags}).
1208
1278
  - §edit-marker-required-on-existing **A markerless EDIT is CREATE-ONLY — there is no easy-clobber path on an existing entry.** A `<L>` marker scopes an EDIT to a range; without one, the body becomes the entry's WHOLE content — legitimate and required for a fresh entry (nothing exists to scope into), but on an EXISTING entry a missing marker is refused **400**, never a silent full replace. A deliberate full rewrite states that intent explicitly: `<1,-1>` resolves through the ordinary marker math to the same whole-content replacement, so the capability is available but cannot be selected by omission.
1279
+ - §edit-line-anchors An anchored EDIT resolves under {§line-anchors} and carries
1280
+ its endpoint checks as a core-private mutation precondition. Otherwise-valid
1281
+ zero/multiple matches and later precondition misses share {§edit-collision};
1282
+ malformed positions and schemes without textual EDIT scopes return 400 before
1283
+ handler invocation, while an upstream current-read failure preserves its
1284
+ status. The model-facing teaching recommends anchors for EDIT because this
1285
+ rejection is deliberate stale-target protection; parser support for anchors
1286
+ on observations does not imply the same recommendation.
1287
+ - §edit-collision Every standard entry EDIT lands by compare-and-swap against
1288
+ the exact channel content used to calculate it, including numeric-only EDITs.
1289
+ A concurrent creator that wins the resource identity or channel, an anchor
1290
+ that no longer identifies exactly one line, a selected endpoint neighborhood
1291
+ that changes before mutation, or a representation that changes in the final
1292
+ check/write gap returns the same neutral **409 `edit-collision`** and preserves
1293
+ the winner's content. Its public detail says only that EDIT collided with
1294
+ another change and directs the model to READ and retry; it does not assign
1295
+ fault or reveal which detection layer won. Concurrent correct workers are an
1296
+ ordinary cause. Core resolves anchors, scheme handlers receive only numeric
1297
+ coordinates, the shared entry mutation owner rechecks selected endpoint
1298
+ neighborhoods against its exact snapshot, and atomic identity/channel claims
1299
+ and storage predicates close the remaining races.
1209
1300
 
1210
1301
  A `file:///` member EDIT diverges from this immediate-write contract: it diffs against the entry snapshot (the body channel, never a fresh disk read) and **proposes** (202) a disk write that lands via a compare-and-swap on accept. See {§membership-edit-write-cas} and the proposal lifecycle {§proposal}. The marker-required rule above applies identically here — an existing file is never markerlessly replaced.
1211
1302
 
1212
1303
  ### §read READ
1213
1304
 
1214
- AST: `{ op: "READ", target, body: MatcherBody | null, signal: tags | null, lineMarker? }`.
1305
+ AST: `{ op: "READ", target, body: null, signal: tags | null, lineMarker? }`.
1306
+
1307
+ Matcher-bearing or path-glob READ syntax has already normalized to canonical
1308
+ FIND before dispatch under {§read-find-normalization}; core has no second READ
1309
+ selection or fan-out path.
1215
1310
 
1216
1311
  - §read-read-content Returns channel content and mimetype.
1217
1312
  - §read-read-404 Returns 404 when the channel is absent.
1218
- - `body` is a resource predicate dispatched per {§matcher-dispatch}.
1219
- - §read-selection-projection `lineMarker` projects text through text-region} after selection. It never limits the content searched or paginates match occurrences. Without a marker, READ returns each selected resource's complete readable content. A miss is 204 before projection; an invalid text region is 416.
1220
- - Semantic READ uses a leading decimal as its optional similarity threshold. The remaining one, two, or four integers are the text projection. Without a leading decimal, semantic selection uses the configured default and every integer component belongs to READ projection. Direct FIND instead applies remaining integers to ranked result positions; only a markerless semantic FIND uses the configured default top-K ({§find-semantic-default-top-k}).
1313
+ - §read-selection-projection READ applies `lineMarker` as text coordinates to one
1314
+ exact target underread-exact-target}. Markerless READ synthesizes
1315
+ `<1,16>`; `<1,-1>` explicitly selects all text. Successful positional reads
1316
+ carry the compact requested/returned extent and available total
1317
+ ({§range-extent}). Anchors resolve under {§line-anchors} before selection. An
1318
+ invalid text region is 416.
1319
+
1320
+ §log-item-tags **Tags classify durable log items.** Under {§log-tag-signal}, FIND, READ, EDIT, COPY,
1321
+ and MOVE strip any leading `+` from every signal term and add the resulting tag
1322
+ to the one log row created for that operation. The row receives its complete
1323
+ deduplicated set even when the operation fails or has no body; the signal never
1324
+ filters candidates, changes a resource, or persists on an entry. OPEN and FOLD
1325
+ use every unsigned signal term as an ALL-tags filter over existing log rows;
1326
+ their optional target and matcher intersect that set. They then strip and add
1327
+ each `+tag` and strip and remove each `-tag` on the exact selected rows while
1328
+ applying the requested visibility. Signed terms never select: a curation
1329
+ operation requires a target, matcher, or unsigned tag. Add and remove terms for
1330
+ the same tag conflict. Successful visibility and classification changes land as
1331
+ one curation event whose exact per-row deltas are durable. Engine policy may
1332
+ apply its separately specified diagnostic classifications, such as `overflow`.
1333
+ Every classification lives once in `log_tags`, is erased with its row, and is
1334
+ copied with log history on fork.
1221
1335
 
1222
1336
  ### §open-fold OPEN / FOLD
1223
1337
 
1224
1338
  AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: null }`.
1225
1339
 
1226
- OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). FOLD collapses a log row to its path; OPEN restores its ordinary packet projection, including any preview bound ({§body-projection}). The canonical full body remains available through READ of the log URI. Non-destructive: rows and bodies persist. On any valid row, applying its current state again or targeting a bodyless row is a successful visibility no-op; malformed targets and nonexistent exact coordinates still fail at their addressing boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1340
+ OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). FOLD collapses a log row to its path; OPEN restores its ordinary packet projection, including any preview bound ({§body-projection}). Both select by target, matcher, and the symmetric ALL-tags filter, then apply the tag changes defined by {§log-item-tags}. The canonical full body remains available through READ of the log URI with `<1,-1>`. Non-destructive: rows and bodies persist. On any valid row, applying its current state again or targeting a bodyless row is a successful visibility no-op; classification changes still land. Malformed targets and nonexistent exact coordinates fail at their addressing boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1227
1341
 
1228
1342
  ### §jsonplurnk The Log's wire format
1229
1343
 
1230
- The `## Log` section renders as a fenced `jsonplurnk` block - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw HEREDOC (`<<:::TAG ... :::TAG`, TAG = the entry's target/log URI), rendered with universal `N:` line prefixes, never as a JSON-escaped string. The carve-out is localized to `body`, so the strip-parser is trivial: after `"body":`, `<<:::TAG` opens and `:::TAG` at column 0 closes; replacing that block with an escaped string recovers strict JSON through `@plurnk/plurnk-contracts`. The body shape is a strict three-state invariant: `"display":"none","body":""` for no body, `"display":"folded"` with the ordinary projection withheld, and `"display":"open","body":HEREDOC` with it shown. A bounded projection also carries `"overflow":"Body content truncated. Use READ log:///<coordinate>/<op> to view the full body."` whether open or folded. The block is data only - no prose leads the fence. `tokens` is the ruler-weight of the row's ordinary packet body: the room OPEN adds and FOLD saves. A FIND's `itemsTokenTotal` is the ruler-weight of the matched entries themselves: the room READing them takes. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/numbered bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body/display state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1344
+ The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every content line begins with a numeric `N:` or anchored `@hash N:` coordinate prefix whose separator is one or more ASCII spaces, and its closing quote appears at column zero before either the object close or a following member. Source quotes, braces, fences, and headings cannot collide with either boundary because source text never occupies column zero after projection; source backticks therefore cannot form a CommonMark closing fence. The fixed opener keeps the packet prefix stable across content changes. The carve-out is localized to `body`, so the strip-parser recognizes `"body":"` followed by a newline, consumes one or more coordinate-prefixed lines, and replaces the raw multiline value with an escaped JSON string while preserving following members to recover strict JSON. The body shape is a strict three-state invariant: `"display":"none","body":""` for no body, `"display":"folded"` with the ordinary projection withheld, and `"display":"open","body":"\n<coordinate>...\n"` with it shown. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an OPEN bounded projection differs from the canonical body, it appends `"chunk":"showing <selected> of <complete>"` after `body`; otherwise it omits `chunk`. Complete-line extents use inclusive two-coordinate line regions. A cut inside a line uses four-coordinate, start-inclusive and end-exclusive regions with 1-based Unicode code-point columns. The row's `path` remains the canonical READ target. The block is data only - no prose leads the fence. `tokens` is the ruler-weight of the row's ordinary packet body: the room OPEN adds and FOLD saves. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page has a different weight. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/coordinate-prefixed bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body/display state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1231
1345
 
1232
- §jsonplurnk-dynamic-fence The opening fence length is **dynamic**: one backtick longer than the longest backtick run in the rendered entries (floor 3). A body can carry arbitrary content — a READ of a doc whose own text opens a column-0 triple-backtick fence — which a fixed opener would let close the block early; a dynamic opener can never be closed by its own body content (CommonMark closes a fence only on a line of at least its own length), independent of the `N:` numbering that incidentally keeps text bodies off column 0.
1346
+ ### §retrieval-packet-metadata READ/FIND packet metadata
1233
1347
 
1234
- ### §model-entry The model's own emission, mirrored back
1348
+ The packet projects one actionable owner for each retrieval fact:
1235
1349
 
1236
- §model-entry-log-curation A `model` log row is the model's **verbatim admitted emission**, mirrored back so it can inspect and curate its own behavior. Actionless, like an `op='error'` row ({§operation-results}): no target, no op executed; `tx` is empty and the emission lives in `rx.content`, typed `text/vnd.plurnk`. **Always born FOLDED** (budget-neutral), line-numbered like all content, and OPEN/FOLD/KILL-able like any log row. Log-KILL clears the `writableBy` gate for the model (the DB-storage curation lever plurnk.md teaches; Log's handler surface — kill only — keeps every other mutating op at 501). The engine writes one after each admitted model turn. Rejected attempts never create model rows.
1350
+ | Result mode | Extent | Result-body evidence | Additional aggregate fact |
1351
+ |---|---|---|---|
1352
+ | line READ | compact `line` range | none | none |
1353
+ | exact-coordinate READ | none | top-level `region` | none |
1354
+ | READ-shaped materialization notice | none | none | generic body `lines` |
1355
+ | catalog/path FIND | compact `resource` range | none | none |
1356
+ | broad matcher FIND | compact `resource` range | per-resource match-location counts | nonzero complete `matchLocationCount` |
1357
+ | exact matcher FIND | compact `matchLocation` range | each row's locator/region | none |
1358
+
1359
+ The compact range is `{ unit, total, requested: [first,last], returned?:
1360
+ [first,last] }` ({§range-extent}); empty results omit `returned`. Transparent
1361
+ coordinates let the model determine whether more material exists and choose
1362
+ its own next request, so packet metadata never prescribes `next`, `complete`,
1363
+ or `all`. FIND range cardinality replaces top-level `items`, `lines`, and
1364
+ `matchingPathCount`; line READ likewise omits the rendered-body `lines` count
1365
+ and its internally resolved whole-line region. Exact READ retains only its
1366
+ region. A failed retrieval's Problem owns its range extension rather than
1367
+ repeating it at top level. Generic `tokens` always weighs the rendered body;
1368
+ generic body `lines` remains available on READ-shaped materialization notices
1369
+ that have no retrieval extent. FIND content weights follow {§jsonplurnk};
1370
+ ordinary bounded bodies expose their displayed and complete chunk extents there.
1237
1371
 
1238
- - §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/)`. Rendered row paths append `/OP` as optional self-documentation, not a fourth resource level: `log:///1/2/*` selects the turn's item rows, while `log:///**/READ` may deliberately filter that decoration.
1239
- - §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — OPEN/FOLD/KILL take a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}) exactly as `READ(worker:///docs/)` fans out a folder: `FOLD(log:///1/2)` folds turn 1/2's rows. A **well-formed glob that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. 400 remains for a malformed target only (no coordinate, no glob, no slash).
1240
- - §log-region-tagging **Named region tagging: FOLD applies, OPEN/FIND filter** — the log's write-op is **FOLD**, because EDIT can't reach engine-written rows (the OP×resource matrix): `FOLD[tag](region)` folds the region AND stamps the tag on it, additively ({§edit-tags-additive}), via `log_tags` (CASCADE-erased with the row on KILL). The read-ops filter: `OPEN[tag]` and `FIND[tag]` select rows carrying EVERY listed tag ({§find-tag-filter-and-semantics}) — a **targetless** `OPEN[tag]` recalls the whole tagged working-set across the worker, a scoped one filters within its glob; an unknown tag matches nothing (204, no-op success). `[tag]`-applies-on-the-write-op / `[tag]`-filters-on-the-read-ops is the same split entries already use (EDIT vs FIND); FOLD merely stands in for EDIT because the log is not an entry scheme. A fork carries a row's tags with its fold-state ({§machine-processes-fork-copies-the-log}). The model curates named working-sets of its own memory: file-away-under-a-name, recall-by-name.
1241
- - §log-curation-set-selection **Set selection, never positional curation** — target/glob, optional body matcher, and (for OPEN) tag filters compose into the affected row set. FOLD's tags apply after selection. OPEN and FOLD have no `<L>` marker and never paginate that set; FIND owns result pagination.
1372
+ ### §model-entry The model's own emission, mirrored back
1242
1373
 
1243
- The worker's **first** model row is exceptional: a born-OPEN turn-0 **exemplar** a minimal worked example (`PLAN` environment `FIND`s `SEND[102]`) the model always opens on, so the grammar can stay thin (the example teaches the syntax, not a heavy grammar). Its `SEND[102]` names the next action, matching the continuation contract. {§model-entry}
1374
+ §model-entry-log-curation A model-emission log row is the model's **verbatim emission**, mirrored back so it can inspect and curate its own behavior. It is an actionless artifact: `op` is null, `attrs.kind="model_emission"` identifies the row, no target exists, `tx` is empty, and the emission lives in `rx.content`, typed `text/vnd.plurnk`. Its exact address is the undecorated three-part coordinate `log:///<L>/<T>/<S>` because no operation exists to append. An admitted emission is **always born FOLDED** (budget-neutral), line-numbered like all content, and OPEN/FOLD/KILL-able like any log row. Log-KILL clears the `writableBy` gate for the model (the DB-storage curation lever plurnk.md teaches; Log's handler surface kill only — keeps every other mutating op at 501). The engine writes one after each admitted model turn. The invalid-emission recovery item under {§emission-admission} mirrors only the latest rejected response, is born FOLDED with `attrs.admission="rejected"`, and is projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
1244
1375
 
1245
- §fold-open-meta-operations **OPEN and FOLD are meta-operationsrender directives, not actions.** They change how the world *displays*, never what it *is* (scrolling, not editing). A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). The emission also survives verbatim in the `model` mirror. A **failed** OPEN/FOLD (bad target or matcher) renders normally with its status errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
1376
+ - §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 `## READ0 (worker:///docs/)`. A rendered operation row appends its canonical model-facing `/OP`, not a fourth resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive suffix is authoritative and a disagreement resolves 404. 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` deliberately filters the canonical suffix.
1377
+ - §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — OPEN/FOLD/KILL take 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: `## FOLD0 (log:///1/2)` folds turn 1/2's rows. OPEN and FOLD may instead take only a tag filter ({§log-item-tags}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. A targetless operation without tags or a matcher is 400.
1378
+ - §log-curation-set-selection **Set selection, never positional curation** — target/glob, optional body matcher, and optional ALL-tags filter compose by intersection into the affected row set. OPEN and FOLD have no `<L>` marker and never paginate that set; FIND owns result pagination.
1246
1379
 
1247
- §kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its emission survives in the `model` mirror. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match error but a malformed coordinate is) renders like any error.
1380
+ §fold-open-meta-operations **OPEN and FOLD are meta-operations log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). Its exact selected target set, each target's pre-event visibility, and the classifications actually added and removed persist with that event; `matched: N` and the authored selector are not the database's sole effect evidence. The operation row, visibility changes, tag changes, and landed effects commit in one database statement. The emission also survives verbatim in its model-emission mirror. A **failed** OPEN/FOLD (bad target, matcher, or tag signal) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
1381
+
1382
+ §kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its emission survives in its model-emission mirror. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match ≠ error but a malformed coordinate is) renders like any error.
1248
1383
 
1249
1384
  ### §log-sensitive-request-evidence Durable request evidence
1250
1385
 
@@ -1259,7 +1394,7 @@ secret detection.
1259
1394
  | Query and authored body | Preserved exactly; they are authored content and URI identity, not structurally identifiable credential slots. |
1260
1395
  | Parser failure | Preserves the structural diagnosis and source position without quoting request-metadata contents ({§path-request-metadata}). |
1261
1396
  | Client, fork, packet, and digest | Consume the stored projection; none owns a second redaction policy. |
1262
- | Provider attempt and `model` mirror | `turn_attempts.response` under {§emission-admission} and the folded row under {§model-entry-log-curation} remain exact forensic evidence and are the explicit exception. |
1397
+ | Model-call evidence and model-emission mirror | `model_calls.response` under {§emission-admission} and the folded row under {§model-entry-log-curation} remain exact forensic evidence and are the explicit exception. |
1263
1398
 
1264
1399
  ### §copy COPY (engine-orchestrated)
1265
1400
 
@@ -1268,17 +1403,20 @@ body: ResourceSelection (destination), signal: tags | null }`.
1268
1403
 
1269
1404
  1. §copy-missing-source-404 Resolve source path, channel, and optional text scope; missing resource or
1270
1405
  channel is 404. A binary marker is not a byte channel and returns 415;
1271
- readable projections are ordinary text sources under {§membership-source-projection}.
1406
+ readable projections are ordinary text sources under
1407
+ {§membership-source-projection}. Source anchors resolve under
1408
+ {§line-anchors}.
1272
1409
  2. Resolve destination path, channel, and optional text scope. Source and
1273
- destination mimetypes must agree or the result is 415.
1410
+ destination mimetypes must agree or the result is 415. Destination anchors
1411
+ resolve independently under {§line-anchors}.
1274
1412
  3. A scoped destination must already exist and is mutated through the
1275
1413
  destination scheme's `editBatch`.
1276
1414
  4. An unscoped destination writes only its selected channel. Existing other
1277
1415
  channels survive.
1278
1416
  - §copy-conflict-409 Different content in that channel is 409.
1279
- - §copy-noop-304 Identical content with no new tag is 304.
1280
- 5. Only explicit `signal` tags are applied, additively, to the destination.
1281
- Source tags are never copied.
1417
+ - §copy-noop-304 Identical content is 304.
1418
+ 5. The signal classifies the COPY log item and never changes either resource
1419
+ ({§log-item-tags}).
1282
1420
 
1283
1421
  §copy-cross-scheme-copy The result is 201 for a new entry, 200 for a write, 304 for an exact no-op, or
1284
1422
  202 when the owning scheme requires proposal review. Same- and cross-scheme
@@ -1292,8 +1430,14 @@ body: ResourceSelection (destination), signal: tags | null }`.
1292
1430
  - §move-relocation-deletes-source MOVE first performs the destination mutation under {§copy}, then removes only
1293
1431
  the selected source region or channel. A whole-channel MOVE deletes the
1294
1432
  source entry only when that was its final channel.
1433
+ - §move-canonical-whole-source The canonical whole-content source scope
1434
+ `<1,-1>` resolves as a whole-channel selection for MOVE: it removes the
1435
+ selected channel and deletes the source entry when that was its final
1436
+ channel. Every other source scope remains regional even when it currently
1437
+ covers all available text; resource deletion is never inferred from extent.
1295
1438
  - A same-channel regional MOVE applies destination insertion and source
1296
- deletion in one same-snapshot `editBatch`; overlapping regions are 409.
1439
+ deletion in one same-snapshot `editBatch`; source and destination anchor
1440
+ preconditions compose against that snapshot, and overlapping regions are 409.
1297
1441
  - A cross-resource destination failure leaves the source untouched. A source
1298
1442
  failure after destination success is an explicit partial failure with
1299
1443
  `destinationWritten: true`. Proposal acceptance/rejection follows the same
@@ -1312,42 +1456,62 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
1312
1456
 
1313
1457
  AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal: tags | null, lineMarker? }`.
1314
1458
 
1315
- - §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns retain native shell behavior. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive folder scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax and READ dispatches it directly. This is an explicit plugin contract, never inferred from URL punctuation: new schemes cannot accidentally turn a root resource into unbounded fan-out. For declared folder schemes the same target contract governs FIND and READ - bare = the entry, folder/glob = a scope.
1459
+ - §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns retain native shell behavior. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive FIND scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax. This is an explicit plugin contract, never inferred from URL punctuation.
1316
1460
  - An exact target resolves to the same canonical `(scheme, pathname)` identity
1317
1461
  as READ, entry CRUD, and any preceding `prepareFind()`. URI authorities are
1318
1462
  identity-bearing: `https://example.com/page` queries
1319
1463
  `(https, /example.com/page)`, never `(https, /page)`.
1320
1464
  - §find-glob-filter-on-content `body` matcher operates on entry content (glob/regex/jsonpath/xpath), per `plurnk.md` "Pattern Filtering"; the path-glob lives in the (target), not the body.
1321
- - §find-semantic-default-top-k Every matcher operates only over the candidate set selected by `(target)` and `[tags]`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies the ordinary FIND result scope - never rank the wider corpus and discard out-of-scope hits afterward, which changes ranking meaning and leaks entries across an exact target. A semantic matcher with no `<scope>` returns the configured `PLURNK_SERVICE_SEMANTIC_TOP_K` highest-ranked results. Otherwise integers retain FIND's positional contract: `<N>` selects result N and `<N,M>` selects the inclusive range. A leading decimal first applies a minimum cosine-similarity threshold; following integers select positions within that ranked threshold set. Thus `<0.7,10,20>` means threshold 0.7 followed by results 10 through 20, while positions 1 through K use the ordinary `<1,K>` range. The FIND render budget remains independent of semantic ranking.
1322
- - §find-tag-filter-and-semantics `signal` is a tag filter; entries match if they have ALL listed tags.
1465
+ - §find-semantic-selection Every matcher operates only over the candidate set selected by `(target)`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies the ordinary FIND result scope. Markerless semantic FIND therefore uses the same `<1,16>` default as every other matcher. Integers retain FIND's positional contract: `<N>` selects result N and `<N,M>` selects the inclusive range. A leading decimal first applies a minimum cosine-similarity threshold; following integers select positions within that ranked threshold set. Thus `<0.7,10,20>` means threshold 0.7 followed by results 10 through 20, while `<0.7>` applies the threshold and the ordinary first-16 page.
1323
1466
  - §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
1324
- - §find-result-catalog-rows Returns
1325
- `FindResult { status, content, mimetype, results, matches, pathnames }`. A
1326
- **body-less** FIND is the **catalog**. Ordinary rows are one per resource:
1327
- `{ path, stream?, tags?, channels: { <uri>: { mimetype, tokens, lines } } }`.
1467
+ - §find-result-projection **The authored target shape determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsTokenTotal, returnedItemsTokenTotal }`:
1468
+
1469
+ | Target | Matcher body | `range.unit` | Result rows |
1470
+ |---|---|---|---|
1471
+ | exact | absent | `resource` | the one catalog channel group |
1472
+ | glob or folder | absent | `resource` | catalog channel groups |
1473
+ | glob or folder | present | `resource` | matching channel groups with `matchLocationCount` on `[0]` |
1474
+ | exact | present | `matchLocation` | flat `{ locator?, region? }` locations |
1475
+
1476
+ A glob or folder remains resource mode when it resolves to one path. An exact
1477
+ target remains location mode when it has many locations. A valid exact match
1478
+ with no addressable location is status 200 with `matchingPathCount: 1`,
1479
+ `matchLocationCount: 0`, and no fabricated row; a matcher selecting no
1480
+ resource is 204. A body-less broad empty catalog survey is status 200; an
1481
+ absent exact resource is 404.
1482
+
1483
+ Inside `FindResult`, `matchingPathCount` and `matchLocationCount` describe the
1484
+ complete selection before pagination; the packet curates those facts under
1485
+ {§retrieval-packet-metadata}. `path` is reserved for resource or channel identity;
1486
+ broad results never nest locations, and exact location rows never repeat the
1487
+ resource path. A **body-less** FIND is the **catalog**. Its outer result array
1488
+ contains one nonempty, flat channel array per resource. Element `[0]` is always
1489
+ the default channel and carries the bare resource path; later elements carry
1490
+ their complete `path#channel` addresses. Each channel is
1491
+ `{ path, mimetype, tokens, lines, parseIssues? }`; `parseIssues` is the
1492
+ positive-only advisory projection of `{§mimetype-parse-issues}` for the exact
1493
+ body derivation under `{§scheme-catalog-parse-issues}`. Resource-level `stream` and broad-match
1494
+ `matchLocationCount` live only on `[0]`. A single-channel resource is therefore
1495
+ a one-element array, with no path-owning wrapper or duplicated channel map.
1328
1496
  A terminal single-star path scope is a one-level map: direct entries retain
1329
- that shape, while deeper first-segment directories collapse to
1330
- `{ path: "dir/**", items, tokens }`, where the selector and both aggregates
1497
+ that shape, while deeper first-segment directories collapse to the one-element
1498
+ group `[{ path: "dir/**", items, tokens }]`, where the selector and both aggregates
1331
1499
  describe the exact recursive subtree. Scope summaries are navigation
1332
- metadata, not resources or hidden READ fan-out matches. A matcher FIND
1333
- retains the same one-row-per-resource unit and adds
1334
- `matches: MatchEvidence[]` ({§matcher-selection-signal}). FIND pagination
1335
- counts selected resources, never occurrences. Resource order is rank for
1336
- `~`semantic and candidate order otherwise; evidence retains dialect order
1337
- and exact duplicates deduplicate. `content` is one valid compact JSON array
1338
- with exactly one top-level item per physical line: objects carry no
1339
- pretty-print whitespace, the opening bracket shares the first row, the
1340
- closing bracket shares the last, and only the `N-1` item-boundary newlines
1341
- are added. Universal packet numbering therefore makes result ordinal N
1342
- addressable as line N, matching `<N>` pagination without a second coordinate
1343
- system. Empty and single-item arrays remain one line.
1344
- - §find-count-not-contents **Over the render budget, FIND returns a count, not
1345
- contents** (`PLURNK_SERVICE_FIND_MAX_MATCHES`). A repo-scale recursive
1346
- FIND cannot enumerate safely. When the selected-resource count exceeds the
1347
- budget, `overflow` and `itemsTokenTotal` carry the count and aggregate weight
1348
- while `results`, `matches`, and `pathnames` are empty; no caller may perform
1349
- hidden work from content the model was denied. The gate is independent of
1350
- model window size. `0`/unset disables it.
1500
+ metadata, not resources. Markerless FIND returns positions 1–16 in the
1501
+ selected unit; `<N,M>` selects an inclusive page and `<1,-1>` explicitly
1502
+ selects all. `range` reports the unit, complete result total, normalized
1503
+ request, and returned positions ({§range-extent}). `itemsTokenTotal` weighs the complete matched set while
1504
+ `returnedItemsTokenTotal` weighs the returned resource page; in exact
1505
+ location mode both weigh the one selected resource once. Resource order is
1506
+ rank for `~`semantic and candidate order otherwise; location order is dialect
1507
+ order and exact duplicates deduplicate. The intended drill-down is broad FIND
1508
+ to choose paths, exact-target FIND to choose locations, then exact READ.
1509
+ `content` uses the shared generated-JSON projection
1510
+ ({§json-result-rendering}), so universal packet numbering makes result
1511
+ ordinal N addressable as line N, matching `<N>` pagination without a second
1512
+ coordinate system. Pagination is the only FIND materialization bound; no
1513
+ hidden complete row or location collection is retained behind the public
1514
+ projection.
1351
1515
 
1352
1516
  ### §send SEND
1353
1517
 
@@ -1362,16 +1526,16 @@ AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, signal: nu
1362
1526
  |---|---|---|---|
1363
1527
  | **102** continue | next turn | next turn | next turn |
1364
1528
  | **200** done | **resolved** — terminal, loop ends | **refused** — Premature-Terminate (KILL to abandon, or wait) | **refused** — forced next turn to see the result |
1365
- | **202** wait | **resolves like 200** a wait on zero things is satisfied; `<-1>+∅` is a bid to hang the agent, folded to done, never honored | **block on the join** — the loop sleeps (`<T>`/`<-1>` bound it, `<P>` polls); its work's conclusion **reawakens the same loop**, prompt intact ({§worker-lifecycle-child-wake}, {§worker-lifecycle-wake-liveness}) | resolves next turn (≈ continue) |
1529
+ | **202** wait | **resolves like 200**, unless this turn successfully FOLDed an empty wait is satisfied, while FOLD continues into the curated next packet | **block on the join** — the loop sleeps (`<T>`/`<-1>` bound it, `<P>` polls); its work's conclusion **reawakens the same loop**, prompt intact ({§worker-lifecycle-child-wake}, {§worker-lifecycle-wake-liveness}) | resolves next turn (≈ continue) |
1366
1530
 
1367
- §wait-obligation-matrix **499** gives up regardless of obligations and cancels the unresolved descendant scope — the model's one self-decided failure ({§state-terms}). The surface is small on purpose. The **one** non-obvious cell is **200 with an obligation in flight** — a contradiction (you claimed done while you owe work), which the engine holds you to via Premature-Terminate below. A child join is bounded by the child's terminal transition; an external stream may carry an explicit `<T,P>` policy.
1531
+ §wait-obligation-matrix **499** gives up regardless of obligations and cancels the unresolved descendant scope — the model's one self-decided failure ({§state-terms}). The surface is small on purpose. The **one** non-obvious cell is **200 with an obligation in flight** — a contradiction (you claimed done while you owe work), which the engine holds you to via Premature-Terminate below. A child join is bounded by the child's terminal transition; an external stream may carry an explicit `<T,P>` policy. A successful same-turn FOLD is synchronous housekeeping, so it does not block an explicit `200`; with `202`, it instead continues as `102` because its context effect is useful only in the curated next packet.
1368
1532
 
1369
1533
  §loop-terminal-authorship **Terminal authorship is explicit when external.**
1370
1534
 
1371
1535
  | `terminated_by` | Meaning | Presentation |
1372
1536
  |---|---|---|
1373
1537
  | `NULL` | The model's own terminal or an engine verdict whose exact result already carries the story. An already-drained join is the model's own successful terminal. | No authorship marker. |
1374
- | `cancel` | An external client cancelled the structured scope ({§methods-loop-cancel}). | COLLECT and the termination delta prepend a cancellation marker to the recorded reason, so cancellation cannot masquerade as a deliverable. The model's prior log rows remain untouched. |
1538
+ | `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. |
1375
1539
 
1376
1540
  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.
1377
1541
 
@@ -1385,7 +1549,7 @@ the loop continue; repeated offenses terminate through the engine's 500.
1385
1549
  | Idle turn | An engine-rail error row with the corrective disposition | One strike |
1386
1550
  | Refused disposition | The final SEND's 409 row with its exact Problem Detail | One strike |
1387
1551
 
1388
- - §send-idle-turn **Idle turn** — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with 200. If you're waiting on a child or stream you spawned, SEND[202] to block on it — a 202 with nothing to wait on simply concludes."*
1552
+ - §send-idle-turn **Idle turn** — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with `## SEND0 [200]`. If you're waiting on a child or stream you spawned, use `## SEND0 [202]` to block on it — a 202 with nothing to wait on simply concludes."* A successful same-turn FOLD is the exception: its `202` continues without a strike so the curated packet can support the next reasoning turn.
1389
1553
  - §send-premature-terminate **Premature terminate — the pending set.**
1390
1554
  Completion is gated by one rule: *nothing pending may be silently
1391
1555
  discarded*. Pending work has two states: **live obligations** (open
@@ -1398,67 +1562,76 @@ the loop continue; repeated offenses terminate through the engine's 500.
1398
1562
  retrieval-only refusal. The pending kind changes the corrective message, not
1399
1563
  rail accounting. `[499]` deliberately abandons regardless.
1400
1564
  - §send-undelivered-child-term **Completion is not delivery.** A result becomes
1401
- observed only after crossing a packet boundary. `SEND[202]` parks only on
1565
+ observed only after crossing a packet boundary. SEND signal `202` parks only on
1402
1566
  live obligations. If work has completed but is unobserved, it continues
1403
1567
  directly to the next packet because the wake edge has already fired; only a
1404
- genuinely empty set resolves immediately like `[200]`.
1405
- - §send-300-choices **SEND[300] is an operator question - a PROPOSAL using the same stop-the-world system as file edits.** Enablement cascades: `PLURNK_QUESTIONS=0` is a servicewide ceiling; otherwise the client affirmatively requests per workspace (`settings.questions: true` at workspace creation), which ALSO injects the required `questions.md` teaching - capability and teaching gate as one ({§teaching-corpus}). An enabled workspace fails doc materialization with the read cause if that source is broken; a disabled workspace does not consume it. Enabled: the `;`-delimited body parses leniently (first segment the question, the rest choices; zero choices = an open question - never malformed), and the ask raises a proposal: dispatch stops the world, `loop/proposal` carries `{question, choices}` in attrs, and the client's accepted proposal body delivers the ANSWER - written into the ask's own model-facing rx (`{"status":200,"body":...}`), read next packet. Reject/timeout resolve through the standard {§proposal} semantics; the turn records a continue either way (never a 300 terminal), and the loop simply proceeds. Loop auto never auto-answers a question - it exists precisely to stop the world for a human, and the workspace opted in. Disabled: refused 409 with a self-decide steer, never a park into the void.
1568
+ genuinely empty set with no successful same-turn FOLD resolves immediately like `[200]`.
1569
+ - §send-300-choices **SEND signal `300` is an operator question - a PROPOSAL using the same stop-the-world system as file edits.** Enablement cascades: `PLURNK_QUESTIONS=0` is a servicewide ceiling; otherwise the client affirmatively requests per workspace (`settings.questions: true` at workspace creation), which ALSO injects the required `questions.md` teaching - capability and teaching gate as one ({§teaching-corpus}). An enabled workspace fails doc materialization with the read cause if that source is broken; a disabled workspace does not consume it. Enabled: the `;`-delimited body parses leniently (first segment the question, the rest choices; zero choices = an open question - never malformed), and the ask raises a proposal: dispatch stops the world, `loop/proposal` carries `{question, choices}` in attrs, and the client's accepted proposal body delivers the ANSWER - written into the ask's own model-facing rx (`{"status":200,"body":...}`), read next packet. Reject/timeout resolve through the standard {§proposal} semantics; the turn records a continue either way (never a 300 terminal), and the loop simply proceeds. Loop auto never auto-answers a question - it exists precisely to stop the world for a human, and the workspace opted in. Disabled: refused 409 with a self-decide steer, never a park into the void.
1406
1570
 
1407
1571
  ### §exec EXEC
1408
1572
 
1409
- AST: `{ op: "EXEC", target (optional input source, program, or cwd), body: string | null (command), signal: string | null (runtime tag), lineMarker (timeout/poll) }`.
1573
+ AST: `{ op: "EXEC", target (optional runtime-specific target), body: string | null (runtime-specific input), signal: string | null (runtime tag), lineMarker (timeout/poll) }`.
1410
1574
 
1411
- §exec-target-routing Engine routes unconditionally to the `exec` scheme and
1412
- canonicalizes `(target)` before effect admission. With no directory override,
1575
+ §exec-target-routing Engine routes unconditionally to the `exec` scheme,
1576
+ resolves the runtime first, and enforces that runtime's required
1577
+ {§executor-invocation} declaration before effect admission. Core owns target
1578
+ realization; neither filesystem type nor body presence may invent a target role
1579
+ the selected runtime did not declare. With no declared directory override,
1413
1580
  `cwd` is the workspace's `project_root`, where the File scheme writes — never
1414
- the daemon's own cwd. A non-file scheme address is an eligible content source
1415
- only when the registered scheme is a data scheme implementing READ. After
1416
- acceptance, core reparses the complete authored address and resolves one exact,
1417
- unscoped READ through that scheme's ordinary handler and addressed context.
1418
-
1419
- | Authored target | Body | Canonical effect target | Accepted executor realization |
1420
- | ------------------------------------- | --------- | ----------------------- | ----------------------------------------------------- |
1421
- | Absent | Non-empty | `null` | Body is the command; target is absent. |
1422
- | Local/file directory | Non-empty | `null` | Directory becomes `cwd`; target is absent. |
1423
- | Local/file file or stat miss | Any | Authored local path | Path is the program/data target; body is its input. |
1424
- | Readable data-scheme address | Empty | `null` | Selected READ content becomes the command. |
1425
- | Readable data-scheme address | Non-empty | Authored address | Selected READ content becomes a local target. |
1426
-
1427
- §exec-source-temporary A non-empty-body data-scheme source is materialized into
1428
- one core-owned temporary file after acceptance. The file lives through the
1429
- executor run and core removes it after the subscription's terminal result has
1430
- settled. A removal failure is reported to daemon diagnostics with its complete
1431
- cause; it cannot rewrite the execution result, stream state, or completion
1432
- wake.
1433
-
1434
- Loop-flag authority follows the same target classification:
1435
-
1436
- | Target class | Schemes that must be active |
1437
- | ------------------------------ | ---------------------------------------- |
1438
- | Absent, local, or `file://` | `exec` |
1439
- | Non-file scheme address | `exec` and the addressed source scheme |
1440
-
1441
- A stat miss means exactly `ENOENT` and takes the file arm so the runtime reports
1442
- its own not-found rather than dispatch returning 400. Any other stat failure
1443
- stops target classification before effect admission with a core-owned 500
1444
- Problem: its bounded diagnostic states the occurrence-specific cause and daemon
1445
- diagnostics retain the complete error. An empty body is legal for a local file
1446
- or scheme command source; it remains a 400 with no target or a directory target.
1447
- For a scheme-data target, the authored address is an opaque target-present
1448
- identity: the executor neither resolves it nor sees it during `run()`; core
1449
- materializes the selected content only after acceptance and supplies that local
1450
- path.
1581
+ the daemon's own cwd.
1582
+
1583
+ | Declared target kind | Authored target | Canonical effect target | Executor realization |
1584
+ | -------------------- | --------------------------------------- | ----------------------- | --------------------------------------------------------- |
1585
+ | Omitted | Any present target | — | Refuse 400 before admission. |
1586
+ | `literal` | Any target | Complete authored string | Preserve that exact string; perform no stat or scheme read. |
1587
+ | `path` | Local or `file://` path | Local path | Pass the path directly. |
1588
+ | `path` | Non-file address | | Refuse 400 before admission. |
1589
+ | `resource` | Local or `file://` path | Local path | Pass the path directly. |
1590
+ | `resource` | Non-file data-scheme address | Complete authored address | Resolve one exact READ after acceptance and pass its temporary local file. |
1591
+
1592
+ A local directory becomes `cwd` with an absent executor target only when the
1593
+ runtime declaration explicitly sets `target.directory: "cwd"`; otherwise it
1594
+ remains the target. Core stats only for that declared rule. `ENOENT` remains a
1595
+ target so the runtime reports its own not-found. Any other stat failure stops
1596
+ before effect admission with a core-owned 500 Problem whose bounded diagnostic
1597
+ states the occurrence-specific cause while daemon diagnostics retain the
1598
+ complete error.
1599
+
1600
+ Body and target requirements come from the same runtime declaration. A runtime
1601
+ with no target declaration refuses a target; required body or target fields are
1602
+ enforced independently; every EXEC requires at least one of them; and an
1603
+ `exclusive` declaration refuses an invocation containing both. A target retains
1604
+ its one declared role whether the body is empty or non-empty. Runtime selection,
1605
+ target validation, and body/target relation failures therefore occur before
1606
+ effect classification or proposal creation.
1607
+
1608
+ §exec-source-temporary A non-file `resource` target is materialized into one
1609
+ core-owned temporary file after acceptance. Core reparses the complete authored
1610
+ address and resolves one exact `<1,-1>` READ through
1611
+ {§universal-read-composition}; internal source consumption never borrows the
1612
+ model-facing 16-line preview. The file lives through the executor run and core
1613
+ removes it after the subscription's terminal result has settled. A removal
1614
+ failure is reported to daemon diagnostics with its complete cause; it cannot
1615
+ rewrite the execution result, stream state, or completion wake.
1616
+
1617
+ Loop-flag authority follows the selected runtime's declaration:
1618
+
1619
+ | Target realization | Schemes that must be active |
1620
+ | ------------------------------------------------------- | -------------------------------------- |
1621
+ | Absent, `literal`, local `path`, or local `resource` | `exec` |
1622
+ | Non-file `resource` | `exec` and the addressed source scheme |
1623
+
1451
1624
  Worker and runtime-stream authorities, query, fragment, request metadata, and
1452
- every other address component therefore retain their owning READ semantics. A
1453
- failed source READ is preserved as the proposal-application failure. A
1454
- successful READ with no string representation is refused 422; `""` remains a
1455
- present representation, although it cannot by itself become an executable
1456
- command.
1625
+ every other component of a `resource` address retain their owning READ
1626
+ semantics. A failed source READ is preserved as the proposal-application
1627
+ failure. A successful READ with no string representation is refused 422; an
1628
+ empty string remains a present representation and is materialized faithfully.
1457
1629
 
1458
- Core calls `effect()` once against this canonical target, without command text,
1459
- stores the resulting fact with the invocation, and reuses it unchanged for
1460
- proposal policy, application, stream registration, and effect-qualified hold
1461
- policy. The post-acceptance materialization path never triggers reclassification.
1630
+ Core calls `effect()` once against the canonical target shown above, without
1631
+ body text, stores the resulting fact with the invocation, and reuses it
1632
+ unchanged for proposal policy, application, stream registration, and
1633
+ effect-qualified hold policy. The post-acceptance materialization path never
1634
+ triggers reclassification.
1462
1635
 
1463
1636
  §exec-registry-resolves The runtime slot (`signal`) selects an executor,
1464
1637
  resolved against the boot-time `ExecutorRegistry`: siblings are discovered and
@@ -1469,7 +1642,7 @@ put a complete command in bare `EXEC`; they are never reinterpreted as shell
1469
1642
  command words. An unavailable runtime is also 501 and carries the probe
1470
1643
  `detail`.
1471
1644
 
1472
- Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor tags merely because they are executables; they are complete shell commands in bare `EXEC` or `EXEC[sh]`. Registered tags exist only for tools that own a distinct body, target, or output contract. {§exec-registry-resolves}
1645
+ Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor tags merely because they are executables; they are complete shell commands under `## EXEC0` or `## EXEC0 [sh]`. Registered tags exist only for tools that own a distinct body, target, or output contract. {§exec-registry-resolves}
1473
1646
 
1474
1647
  **Timeout and poll — `<T,P>` on the `<L>` slot (grammar 0.74.20).** EXEC
1475
1648
  repurposes the line-marker slot as `<timeout, poll>` in **seconds**, the same
@@ -1485,10 +1658,10 @@ before the turn's own spawns, so it never survives into the subsequent turn;
1485
1658
  its terminal output surfaces born-OPEN like any close ({§exec-stream}).
1486
1659
 
1487
1660
  §exec-poll `P` (`mark[1]`) is the **poll cadence**, stored on the subscription.
1488
- While the loop is blocked on a `SEND[202]` wait for that stream, the daemon arms
1661
+ While the loop is blocked on a SEND signal `202` wait for that stream, the daemon arms
1489
1662
  a per-worker timer for the tightest open poll cadence and resumes the blocked
1490
- loop every P seconds, floored by `PLURNK_SERVICE_EXEC_WAIT_MS` so it cannot tick
1491
- faster than a turn settles, to inspect progress. It does **nothing while the
1663
+ loop every P seconds, floored by `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS` so it cannot tick
1664
+ faster than the optimistic settlement scale, to inspect progress. It does **nothing while the
1492
1665
  loop is active** because ambient stream deltas already surface progress. An
1493
1666
  open stream without `P` uses exponential backoff
1494
1667
  (`PLURNK_SERVICE_EXEC_POLL_SEC` and `PLURNK_SERVICE_EXEC_POLL_TURNS`); explicit
@@ -1512,11 +1685,31 @@ edge. Stream closure remains a wake edge under every poll policy.
1512
1685
 
1513
1686
  §worker-auto-name **Auto-names are id-free ordinals** — worker names are the addressable authority, so an auto-name is `<prefix>-<N>` (per-workspace monotonic count, the fork `<parent>-fork-<N>` pattern), never a timestamp-hash that would leak machine identity through the hostname. The semantic suffix remains intact; when the complete name would exceed `WORKER_NAME`, generation shortens only the inherited prefix until the predicate admits it. Auto-names never reuse an existing literal and pass through {§worker-name-minting} like explicit names. Name selection and worker creation are one atomic claim: concurrent allocators receive distinct literals, while concurrent ensures of a workspace's default conversation converge on one root worker.
1514
1687
 
1515
- §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 the stream's new bytes each turn, {§exec-stream}), never a same-turn receipt.
1688
+ §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.
1516
1689
 
1517
- §exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*. Each turn the environment-observation injector reads each owned channel from its byte cursor and publishes the new bytes as an `origin=plurnk` READ at `<runtime>:///<coord>#<channel>`. Streaming deltas are folded; the terminal delta is born OPEN. The row obeys the universal body projection ({§body-projection}): its packet body is bounded and its exact canonical body remains READable through the row's log URI. A stream that closes before a same-turn wait remains pending until this terminal READ crosses the next packet boundary. The EXEC row separately records the command.
1690
+ After all non-SEND operations dispatch, the initiating turn applies {§worker-optimistic-settlement} to only the EXEC streams it started, then dispatches its terminal SEND 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.
1518
1691
 
1519
- `KILL(<runtime>:///<loop>/<turn>/<seq>)` cancels an active subprocess via
1692
+ §exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*.
1693
+ Each turn the environment-observation injector publishes newly publishable content
1694
+ from each owned channel as an `origin=plurnk` READ at
1695
+ `<runtime>:///<coord>#<channel>`, preserving the channel's current mimetype:
1696
+
1697
+ | channel mimetype | while active | at terminal state |
1698
+ |---|---|---|
1699
+ | `text/*` (including `text/stream`) | every new text segment | every remaining segment |
1700
+ | `application/jsonl` or `application/x-ndjson` | complete newline-terminated records | every remaining record |
1701
+ | every other mimetype | nothing | the complete atomic document |
1702
+
1703
+ The per-channel cursor advances only through content actually published, so an
1704
+ active atomic document or trailing partial JSONL record never reaches the model
1705
+ as malformed structured data. Ongoing observations are folded and a terminal
1706
+ observation is born OPEN; a terminal state with no newly publishable body still
1707
+ produces one conclusion row. Every READ then obeys {§body-projection} and
1708
+ therefore renders its selected result complete. A stream that closes before a
1709
+ same-turn wait remains pending until this terminal READ crosses the next packet
1710
+ boundary. The EXEC row separately records the authored invocation.
1711
+
1712
+ `## KILL0 (<runtime>:///<loop>/<turn>/<seq>)` cancels an active subprocess via
1520
1713
  the subscription registry's stored controller. A terminal stream is immutable:
1521
1714
  499 returns 410 (already killed), every other terminal status returns an RFC
1522
1715
  9457 409 Problem carrying `terminalStatus`, and an unknown address returns 404.
@@ -1524,8 +1717,8 @@ The runtime scheme participates in the durable lookup; a completed `sh:///`
1524
1717
  stream cannot fall through an internal `exec`-only query. {§stream-control}
1525
1718
 
1526
1719
  §exec-env-scoped **Scoped environment.** An EXEC subprocess inherits the *project's* environment — its `.env`, the standard shell vars — so the model's commands run as the project expects; but never plurnk's own secrets: the provider API keys and `PLURNK_*` config are stripped before the spawn, so a model-executed command can't `printenv` the engine's keys. The service owns the scoping policy (the denylist); the executor spawns with the env it is handed.
1527
- - §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 `EXEC + SEND[102]` as ever; the wake-shaped world simply arrives one packet sooner. Lives at the post-EXEC breath seam in `runLoop`, upstream of `PLURNK_SERVICE_EXEC_WAIT_MS`. 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.
1528
- - §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry (writeEntry; tags **UNIONED** across writes — a re-seen URL keeps its history of query slugs), then journals ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `tokens` = the content's count, `attrs` carrying the tags plus `kind:"entry_materialized"`. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked byte primitive, accepts a present MIME-rendered response, and lazily tries browser rendering only when that projection is absent {§html-materialization}. A failed acquisition, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype). **No page body ever rides a packet**; the announcement is the folded row's meta (path + tokens + tags), and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
1720
+ - §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 EXEC followed by SEND signal `102` as ever; 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.
1721
+ - §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry, then journals ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `tokens` = the content's count, and `attrs.kind="entry_materialized"`. The requested tags classify that journal row under {§log-item-tags}; they never become resource metadata or duplicate into attrs. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked WebFetcher and accepts its model-facing body and available source/evidence channels {§html-materialization}. Generic public HTML follows the same origin-Markdown, configured Tavily, and local-projection routes as exact HTTP acquisition. A failed acquisition, body-production failure, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype) and grants no provider authority. **No page body ever rides a packet**; the announcement is the folded row's path, weight, and log classifications, and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
1529
1722
 
1530
1723
  ### §proposal The proposal lifecycle
1531
1724
 
@@ -1541,7 +1734,7 @@ stream cannot fall through an internal `exec`-only query. {§stream-control}
1541
1734
 
1542
1735
  | decision | state | `status_rx` | default outcome | effect |
1543
1736
  |---------------------------------|---|---|---|---|
1544
- | §proposal-accept-applies accept | `resolved` | 200 | — | runs the scheme's **`applyResolution`** — the real side effect (disk write, exec spawn). A failing apply (≥400) downgrades to reject, carrying the apply's own outcome — e.g. a member EDIT's `write_conflict` from its write-back compare-and-swap ({§membership-edit-write-cas}) — or `apply_failed` when it names none. |
1737
+ | §proposal-accept-applies accept | `resolved` | 200 | — | runs the scheme's **`applyResolution`** — the real side effect (disk write, exec spawn). A failing apply (≥400) downgrades to reject, carrying the apply's own outcome — e.g. a member EDIT's `edit_collision` from its write-back compare-and-swap ({§membership-edit-write-cas}) — or `apply_failed` when it names none. |
1545
1738
  | §proposal-reject-fails reject | `failed` | 400 | `rejected` | none — the action did not occur. |
1546
1739
  | §proposal-cancel-aborts cancel | `cancelled` | 499 | `loop_aborted` | none — the loop is abandoning. |
1547
1740
 
@@ -1589,7 +1782,7 @@ Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination, but
1589
1782
 
1590
1783
  ### §subscriptions Subscriptions
1591
1784
 
1592
- §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. `SEND[499]`, 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.
1785
+ §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. SEND signal `499`, 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.
1593
1786
 
1594
1787
  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?)` validates and persists the exact universal operation result, settles channel state, closes the durable row, 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. 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.
1595
1788
 
@@ -1612,12 +1805,13 @@ Model sees lifecycle events in the `log` section per turn.
1612
1805
 
1613
1806
  ### §deep-slices Deep slices on demand
1614
1807
 
1615
- `<<READ(https://feed.example/x#body)<N-M>:…:READ` pulls a slice into a log row when the model wants a specific line-range of an SSE stream.
1808
+ `## READ0 (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.
1616
1809
 
1617
- ### §stream-control SEND for stream control
1810
+ ### §stream-control Stream control and writes
1618
1811
 
1619
- - **Cancel:** `<<SEND[499](https://feed.example/x)::SEND` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
1620
- - **Write:** `<<SEND[200](wss://feed/x):body:SEND` pipes body into active connection (WS, exec stdin, etc.).
1812
+ - **Cancel:** `## SEND0 [499] (https://feed.example/x)` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
1813
+ - **WebSocket write:** `## EDIT0 (wss://feed/x)` or `## SEND0 [200] (wss://feed/x)` with a body sends one whole text frame through the active owner. SEND can follow the opening READ in the same turn; EDIT runs before READ ({§op-mode-phases}) and therefore addresses an owner already open at turn start.
1814
+ - **Other stream write:** `## SEND0 [200] (…)` remains scheme-defined, including exec stdin.
1621
1815
 
1622
1816
  ### §stream-constraints Engine constraints
1623
1817
 
@@ -1658,14 +1852,14 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
1658
1852
  **Lives in SQL:**
1659
1853
  - Render queries — log assembly + the manifest catalog.
1660
1854
  - Cross-scope path collision (CHECK/trigger → 409).
1661
- - Cost rollups (denormalized USD; atomic on turn close).
1855
+ - Logical model-call identity plus cardinal physical provider-request lifecycle and immutable settlement constraints.
1662
1856
  - Sequence number issuance (1-based per grammar).
1663
1857
  - Entry-vs-log integrity.
1664
1858
 
1665
1859
  **Lives in TS:**
1666
1860
  - Status-bubble rules (`turn.status` → `loop.status` → `worker.status` → `workspace.status`). Engine UPDATEs explicitly; CHECK constraints enforce; triggers fight branching state machines.
1667
1861
  - Tokenization (provider-bound; hot-swap re-tokenizes per {§tokenomics}).
1668
- - Provider dispatch + response normalization.
1862
+ - Provider dispatch, request-accounting validation, and exact-decimal aggregate projection through the shared contracts-owned path.
1669
1863
  - Scheme-handler invocation (connections, subprocesses, fetch).
1670
1864
  - Plugin loading ({§plugin-discovery}).
1671
1865
  - Stream AbortController lifecycle.
@@ -1749,7 +1943,7 @@ scheme. External schemes are discovered through
1749
1943
  dispatcher contract.
1750
1944
 
1751
1945
  The executor registry discovers installed runtimes, probes availability, and
1752
- routes `EXEC[<runtime>]`; core contributes orchestration and the output-scheme
1946
+ routes `## EXEC0 [<runtime>]`; core contributes orchestration and the output-scheme
1753
1947
  adapter, not runtime implementations. Optional and third-party leaves extend
1754
1948
  each family by installation and discovery; they never require a framework or
1755
1949
  service manifest edit.
@@ -1771,8 +1965,8 @@ service manifest edit.
1771
1965
 
1772
1966
  - Channel state (`static`/`active`/`closed`/`errored`) — persisted channel metadata owned by core and exposed through the schemes capability contract ({§channel-state}).
1773
1967
  - Backpressure caps — none ({§stream-constraints}).
1774
- - Stream cancel — `SEND[499]` ({§stream-control}).
1775
- - Delete — `KILL` (entry-KILL, the canonical delete, {§move}); `SEND[410]` also deletes as a side-effect ({§send-dispatch}).
1968
+ - Stream cancel — SEND signal `499` ({§stream-control}).
1969
+ - Delete — `KILL` (entry-KILL, the canonical delete, {§move}); SEND signal `410` also deletes as a side-effect ({§send-dispatch}).
1776
1970
  - §loop-flags-effective-read Per-loop flags — `loops.flags` persists a partial JSON object; every runtime policy read expands it over contracts-owned `DEFAULT_LOOP_FLAGS` and validates the complete `LoopFlags` before use. Missing rows or invalid values fail with the owning loop coordinate and cause. Raw archival copies and forensic rendering do not interpret policy.
1777
1971
  - Default-channel wire rendering — {§channel-selection}.
1778
1972
 
@@ -1796,7 +1990,7 @@ Node's pre-script env-file form and the executable's post-script form share the
1796
1990
 
1797
1991
  §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), applies it set-if-unset under every operator source, and renders the assembled catalog to `~/.plurnk/.env.defaults`. The catalog is machine-owned, regenerated each boot, and never read back as configuration. A key claimed by two packages fails boot naming both. With the reader-declares discipline, each key has one implementation and one defaults owner.
1798
1992
 
1799
- Model selection: separate alias cascade in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` declares; `PLURNK_MODEL=<alias>` selects. Aliases live in `.env`, not `.env.defaults` (operator-specific).
1993
+ Model selection: separate alias cascade in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` declares; `PLURNK_MODEL=<alias>` selects. Optional `PLURNK_MODEL_CHILD=<alias>` selects the default child provider; unset means inherit the spawning loop's provider. Aliases and selections live in `.env`, not `.env.defaults` (operator-specific).
1800
1994
 
1801
1995
  | Var | Default | Purpose |
1802
1996
  |-------------------------------------------------------------|---------|---------|
@@ -1807,23 +2001,26 @@ Model selection: separate alias cascade in `ProviderRegistry` ({§provider-insta
1807
2001
  | `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts cumulatively across every `202` park/resume. |
1808
2002
  | `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. PLAN and the final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
1809
2003
  | §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | `86400000` | ms wall-clock budget for a single core loop: expiry aborts the loop signal mid-flight (a stuck `generate` included) and the loop terminates `504 loop_timeout` — a legible engine terminal, kin to the exec `<T>` reap's 504 ({§exec-timeout}). |
1810
- | `PLURNK_SERVICE_MAX_STRIKES` | `3` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
1811
- | `PLURNK_SERVICE_EMISSION_ATTEMPTS` | `3` | Completed provider responses allowed beneath one engine turn before an untrustworthy model-turn frame terminates the loop. Bounded interior operation errors are admitted and do not spend this budget. Independent of strikes. |
2004
+ | `PLURNK_SERVICE_MAX_STRIKES` | `6` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
2005
+ | `PLURNK_SERVICE_EMISSION_ATTEMPTS` | `3` | Completed provider responses allowed beneath one engine turn before an untrustworthy model-turn frame exhausts admission. Bounded interior operation errors are admitted and do not spend this budget. Consecutive exhaustion after the one informed recovery turn terminates independently of strikes. |
1812
2006
  | `PLURNK_SERVICE_PREVIEW_LINES` | `16` | Maximum lines in an ordinary bounded log-body projection ({§body-projection}). |
1813
- | `PLURNK_SERVICE_PREVIEW_CHARS` | `1280` | Maximum characters in an ordinary bounded log-body projection; independently contains single-line bodies ({§body-projection}). |
2007
+ | `PLURNK_SERVICE_PREVIEW_CHARS` | `2560` | Maximum Unicode code points in an ordinary bounded log-body projection, with CRLF treated as one indivisible separator; independently contains single-line bodies ({§body-projection}). |
2008
+ | `PLURNK_SERVICE_PROMPT_PROJECTION` | `25%` | Aggregate ruler-weight share of the enforced packet budget available to automatic prompt-body projection ({§prompt-projection}); alias-scoped overrides are supported. |
2009
+ | `PLURNK_SERVICE_LINE_ANCHOR_CONTEXT_LINES` | `2` | Complete neighboring lines hashed on each side of a model-facing line anchor ({§line-anchors}). |
2010
+ | `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | `2` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
1814
2011
  | `PLURNK_SERVICE_MIN_CYCLES` | `3` | Min repetitions before cycle detection fires ({§engine-rails}). |
1815
2012
  | `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | `4` | Max period length cycle detection examines ({§engine-rails}). |
1816
2013
  | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
1817
2014
  | `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | `32768` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
1818
2015
  | `PLURNK_SERVICE_MD_<ALIAS>` | (unset) | Operator reference doc: materializes `<path>` as `worker://plurnk/<ALIAS>.md`, auto-READ into every model worker's turn 0 ({§actor-boundary-doc-injection}). `~` expands to home. |
1819
- | `PLURNK_SERVICE_FILES_ITEMS` | `-1` | Turn-0 catalog preview. Folder-capable schemes render a complete one-level `*` map with `dir/**` rollups; kernel docs remain recursive. `-1` = complete maps; positive `N` caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
2016
+ | `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}). |
1820
2017
  | `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}). |
1821
2018
 
1822
2019
  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.
1823
2020
 
1824
2021
  **Two override semantics — ceiling vs default.** Which kind a var is determines what "override" means across the cascade:
1825
2022
  - **Ceiling** (most-restrictive-wins) — an operator-set hard bound nothing downstream may exceed: not a lower-precedence file, not a per-workspace constraint, not a per-call seam argument. `PLURNK_SERVICE_GIT_ALLOWED` ({§operator-config-git-ceiling}), `PLURNK_SERVICE_MAX_COMMANDS`, `PLURNK_SERVICE_MAX_STRIKES`, and `PLURNK_SERVICE_MAX_TURNS` (`-1` ships it off; a positive value caps the per-call request). The sandbox/cost guarantee: the operator caps it; no client widens it.
1826
- - **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({alias})` request overrides it), `PLURNK_SERVICE_REQUIREMENTS` (the per-call requirements default), and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
2023
+ - **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({alias})` request overrides it) and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
1827
2024
 
1828
2025
  §operator-config-shipped-defaults **The shipped `.env.defaults` is itself under
1829
2026
  test.** It has no active `PLURNK_SERVICE_MD_*` doc alias because policy is a
@@ -1838,14 +2035,14 @@ template both ways: every `PLURNK_SERVICE_*` the service reads has a
1838
2035
  declared `PLURNK_SERVICE_*` is read. A half-landed rename therefore fails a test
1839
2036
  instead of a user's boot, and a dead knob cannot ship.
1840
2037
 
1841
- §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: semantic search enabled, complete catalog orientation, automatic Git membership when the operator ceiling permits Git, and ambient operator-file docs/packet notes cleared. Configuration with a narrower or variable owner stays outside it:
2038
+ §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: Turboderp, semantic search enabled, complete catalog orientation, automatic Git membership when the operator ceiling permits Git, and ambient operator-file docs/packet notes cleared. Configuration with a narrower or variable owner stays outside it:
1842
2039
 
1843
2040
  | Owner | Configuration |
1844
2041
  |---|---|
1845
- | `.env.test` | Universal real-model gate posture only; no aliases, routes, secrets, model tuning, or cost/sandbox ceilings. |
2042
+ | `.env.test` | Safe default model selection and universal real-model gate posture; no alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
1846
2043
  | Live/demo scripts | The repository personality path and runner topology. |
1847
2044
  | Benchlets | Their snapshotted policy, workspace restrictions, and task-specific exceptions; direct env wins over the profile. |
1848
- | Operator env/shell | Model selection, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
2045
+ | Operator env/shell | Model alias declarations and explicit selection overrides, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
1849
2046
  | `test/setup.ts` | Mock-only alias, envelope, resource, storage, and isolation fixtures; unit/integration never consume the real-model profile. |
1850
2047
 
1851
2048
  The profile does not repeat `NODE_OPTIONS`: runner selection belongs to the invoking command, and a process-global Node option would leak into the daemon and its children. Hard ceilings such as max turns, max commands, and Git denial remain operator-owned; harnesses bound paid experiments through their per-call contract and never widen a configured ceiling here.
@@ -1890,7 +2087,7 @@ The composition families remain distinct so one setting's semantics never
1890
2087
  leak into another.
1891
2088
 
1892
2089
  *Defaults — explicit-wins (the client replaces/merges freely):*
1893
- - §operator-config-workspace-files-items `settings.filesItems` (number) **replaces** `PLURNK_SERVICE_FILES_ITEMS` for the workspace: a one-shot opens clean (`0`, no preview), a workspace full (`-1`), or with the file list capped (`N`, memory still full). A single scalar — the client value wins outright.
2090
+ - §operator-config-workspace-files-items `settings.filesItems` (number) **replaces** `PLURNK_SERVICE_FILES_ITEMS` for the workspace: a one-shot opens clean (`0`, no preview), with ordinary markerless pages (`-1`), or with the file list explicitly capped (`N`, other surveys remain markerless). A single scalar — the client value wins outright.
1894
2091
  - §operator-config-workspace-md-docs `settings.mdDocs` (`[{alias, content}]`) **unions** with the server's `PLURNK_SERVICE_MD_*` docs, keyed by alias — a client adds its own repo docs atop the operator's systemwide policy doc. On alias collision the client wins before I/O (a deliberate shadow), so the unselected operator path is not read; every selected non-empty operator path is required, and absence or another read failure rejects materialization with its cause. The client sends content (it owns the file), not a path.
1895
2092
 
1896
2093
  *Ceilings — most-restrictive-wins (the client may only narrow, never widen):*
@@ -1968,7 +2165,7 @@ Its function names are transport-neutral library calls, not public wire names.
1968
2165
  | §methods-event-subscribe Events | `subscribeToEvents(handler) -> unsubscribe` | Subscribes to the raw event source in {§notifications}. A subscriber failure is logged and cannot re-enter engine control flow. |
1969
2166
  | §proposal-list Proposals | `pendingProposals(workspaceId)` | Intersects durable proposed rows with the lifecycle owner's live resolution waiters, then returns their validated {§proposal-projection}; persistence alone cannot advertise an unresolvable client interrupt. |
1970
2167
  | §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution)` | Validates and delivers one accept, reject, or cancel decision to the engine. An unknown or already-resolved id fails; the client protocol owns how the decision arrived. |
1971
- | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, maxTurns?, flags?, openPaths?, alias?, model? })` | Validates a model worker and provider selection, persists the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
2168
+ | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, maxTurns?, flags?, openPaths?, alias?, model?, childAlias?, childModel? })` | Validates a model worker and provider policy, persists it with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
1972
2169
  | §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)` | Begins durable structured cancellation of the worker tree and reaps its process-local scopes. The boolean reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. |
1973
2170
  | §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, statements })` | Dispatches already-parsed grammar statements as one client action and one journal segment. Every statement is an ordered turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep that promise and segment open until resolution. Core exposes no per-op method family. |
1974
2171
  | Client observation | `look({ workspaceId, workerId, statement })` | Runs an already-parsed READ through the full resolver without a log row. A non-READ statement is rejected ({§op-look}). |
@@ -2041,6 +2238,16 @@ loop with a conflicting selection fails before work is accepted. Provider
2041
2238
  instances are cached; no resume path substitutes a boot default for missing or
2042
2239
  malformed durable selection.
2043
2240
 
2241
+ §methods-loop-run-child-provider **Child-provider selection is one durable
2242
+ subcall policy.** Optional `childModel` (client-resolved `<provider>/<model>`, wins) or
2243
+ `childAlias` selects the provider for every WORK/FORK descendant and BARE inference; omitted uses
2244
+ `PLURNK_MODEL_CHILD`, while explicit `childAlias: null` means inherit. Core
2245
+ persists the resolved policy on each loop. A child runs on that provider and
2246
+ carries the same policy deeper; inherit uses the spawning loop's provider and
2247
+ remains inherit. BARE consumes the selection without spawning a child. Packet admission is unchanged: a smaller WORK is valid when
2248
+ its packet fits, and an oversized inherited FORK terminates through the ordinary
2249
+ child-loop result without preflight assembly or provider fallback.
2250
+
2044
2251
  §methods-log-coordinate **Log coordinate.** Every `LogEntry` returned by
2045
2252
  `readLog` or emitted through `log/entry` carries `loop_seq` and `turn_seq`
2046
2253
  beside database ids, so a client can render and resolve the logical `L/T/S`
@@ -2048,26 +2255,28 @@ coordinate without fetching all rows and matching locally.
2048
2255
 
2049
2256
  §methods-log-entry-wire **Log entry wire fidelity.** `readLog` and `log/entry`
2050
2257
  preserve causal `source` and parse the row's JSON `attrs` into structured data;
2051
- client interfaces do not reconstruct either field from operation or origin.
2258
+ they also project the row's complete sorted `tags` classification. Client
2259
+ interfaces do not reconstruct these fields from operation or origin.
2052
2260
 
2053
2261
  §op-look **LOOK ownership.** A client-interface module owns the public LOOK
2054
2262
  spelling and grammar parsing. It rewrites a valid LOOK statement to READ and
2055
2263
  hands the AST to core's `look`; core owns the full resolver and the no-log
2056
2264
  invariant. The internal closed, rowless observation segment supplies an honest
2057
2265
  numeric loop coordinate for relative `log:///` addressing without leaving
2058
- active lifecycle behind.
2266
+ active lifecycle behind. LOOK text anchors resolve through the same
2267
+ {§line-anchors} path as READ.
2059
2268
 
2060
2269
  ### §notifications Core events
2061
2270
 
2062
2271
  | Event | Payload | When fired |
2063
2272
  |--------------------------------------------------------------|---------|------------|
2064
2273
  | §notifications-log-entry-notify `log/entry` | `{ entry: LogEntry }` | A `log_entries` row is committed. |
2065
- | §notifications-loop-terminated `loop/terminated` | `{ workerId, loopId, result, hitMaxTurns, turnIds, usage, attributions }` | One loop reaches a terminal state. `result` is the exact universal operation result, including its RFC 9457 Problem Details on failure. `attributions` is the sorted union of exact provider-request evidence ({§attribution}), separate from `usage`. Worker and loop are an inseparable owning coordinate. |
2066
- | `loop/proposal` | contracts-owned `ProposalProjection` | Dispatch pauses on a durable 202 proposal. `disposition` is the sole authority for whether a client presents review UI; live and reconnect share {§proposal-projection}. |
2067
- | `workspace/created` | `{ id, name, projectRoot }` | A workspace is created. This is the only current global event. |
2068
- | `workspace/branch-batch` | Branch-batch lifecycle payload | A branch batch enters queued, running, completed, failed, or recovery-required state. |
2069
- | §notifications-stream-event-on-channel-change `stream/event` | `{ entryId, target, channel, state, contentLength, mimetype?, loop_seq?, turn_seq?, sequence? }` | Channel content grows or channel state transitions. `target` is the canonical entry URI; the optional coordinate is copied from schemes whose addresses carry one. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic plugin notification capability does not require it. It carries metadata, not content; consumers use `readEntry` for bytes. |
2070
- | §notifications-stream-concluded `stream/concluded` | `{ entryId, target, subscriptionId, scheme, result, summary, wakeAction, wakeLoopId?, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `target` is the canonical entry URI; the optional coordinate is copied from schemes whose addresses carry one, so clients never parse it back out of `target`. Exact result truth is preserved; `wakeAction` records whether core resumed a parked loop, folded into an active loop, skipped an aborted/cancelled worker, or found no loop. |
2274
+ | §notifications-loop-terminated `loop/terminated` | `{ workerId, loopId, result, hitMaxTurns, turnIds, usage: { accounting, contextTokens, promptBudget, meta }, attributions }` | One loop reaches a terminal state. `result` is the exact universal operation result, including its RFC 9457 Problem Details on failure. `accounting` is the loop's contracts-owned {§provider-accounting}; `contextTokens` and `promptBudget` are the latest-turn gauge pair, and `meta` is that turn's opaque provider bag. `attributions` is the sorted union of exact provider-request evidence ({§attribution}), separate from accounting. Worker and loop are an inseparable owning coordinate. |
2275
+ | §notifications-loop-proposal `loop/proposal` | contracts-owned `ProposalProjection` | Dispatch pauses on a durable 202 proposal. `disposition` is the sole authority for whether a client presents review UI; live and reconnect share {§proposal-projection}. |
2276
+ | §notifications-workspace-created `workspace/created` | `{ id, name, projectRoot }` | A workspace is created. This is the only current global event. |
2277
+ | §notifications-workspace-branch-batch `workspace/branch-batch` | Branch-batch lifecycle payload | A branch batch enters queued, running, completed, failed, or recovery-required state. |
2278
+ | §notifications-stream-event-on-channel-change `stream/event` | `{ entryId, workerId, target, channel, state, contentLength, mimetype?, loop_seq?, turn_seq?, sequence? }` | Channel content grows or channel state transitions. `workerId` is the entry owner and read perspective; `target` is its canonical URI. The optional coordinate is copied from schemes whose addresses carry one. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic plugin notification capability does not require it. It carries metadata, not content; consumers read bytes from the stated worker perspective. |
2279
+ | §notifications-stream-concluded `stream/concluded` | `{ entryId, workerId, target, subscriptionId, scheme, result, summary, wakeAction, wakeLoopId?, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `workerId` identifies the entry owner; `target` is its canonical URI. The optional coordinate is copied from schemes whose addresses carry one, so clients never parse it back out of `target`. Exact result truth is preserved; `wakeAction` records whether core resumed a parked loop, folded into an active loop, skipped an aborted/cancelled worker, or found no loop. |
2071
2280
  | §notifications-notice-event `notice/event` | `{ loopId, notice: Notice }` | A transient observation or progress notice occurs. It cannot alter durable history, scheduling, recovery, or model-visible failure truth. |
2072
2281
 
2073
2282
  §notifications-stream-event-failure-isolation The plugin-facing
@@ -2136,12 +2345,12 @@ Conditional absence never reorders the surviving default sections.
2136
2345
  | Order | Slot | Section | Wire contract |
2137
2346
  |------:|:-------|:----------------------|:--------------|
2138
2347
  | 1 | system | `definition` | Framework definition; leads the most stable prefix. |
2139
- | 2 | system | `tools` | Executable capability sheet for this loop. |
2140
- | 3 | system | `optional-operations` | Present only when optional operations are enabled. |
2141
- | 4 | system | `schemes` | Active scheme catalogue. |
2142
- | 5 | system | `inject` | Present only when operator notes are configured. |
2143
- | 6 | system | `system-policy` | Operator policy; empty content is omitted on the wire. |
2144
- | 7 | system | `project-policy` | Project policy; empty content is omitted on the wire. |
2348
+ | 2 | system | `system-policy` | Operator policy; empty content is omitted on the wire. |
2349
+ | 3 | system | `project-policy` | Project policy; empty content is omitted on the wire. |
2350
+ | 4 | system | `tools` | Executable capability sheet for this loop. |
2351
+ | 5 | system | `optional-operations` | Present only when optional operations are enabled. |
2352
+ | 6 | system | `schemes` | Active resource catalogue. |
2353
+ | 7 | system | `inject` | Present only when operator notes are configured. |
2145
2354
  | 8 | user | `log` | Append-mostly model-visible history. |
2146
2355
  | 9 | user | `child-streams` | Per-turn status; empty content is omitted. |
2147
2356
  | 10 | user | `child-workers` | Per-turn status; empty content is omitted. |
@@ -2150,16 +2359,14 @@ Conditional absence never reorders the surviving default sections.
2150
2359
  | 13 | user | `git` | Per-turn workspace status; empty content is omitted. |
2151
2360
  | 14 | user | `budget` | Model-facing packet pressure; omitted when capacity is unknown. |
2152
2361
  | 15 | user | `prompt` | Current prompt-entry pointers. |
2153
- | 16 | user | `requirements` | Syntax recap deliberately nearest generation. |
2154
2362
 
2155
2363
  The order favors prefix-cache locality where semantics permit: the definition
2156
- leads capability and privileged policy, while the append-mostly log leads the
2157
- volatile user-status clump. It does **not** claim that every system byte is
2364
+ and privileged policy lead loop-dependent capabilities, while the append-mostly
2365
+ log leads the volatile user-status clump. It does **not** claim that every system byte is
2158
2366
  immutable or that the complete packet is globally monotone in volatility:
2159
- capabilities, operator notes, and policies can change, and the stable recap is
2160
- deliberately last for model recency. Trust is a separate admission rule. The
2161
- system slot contains trusted control-plane material; attacker-reachable content
2162
- stays in the user slot.
2367
+ capabilities, operator notes, and policies can change. Trust is a separate
2368
+ admission rule. The system slot contains trusted control-plane material;
2369
+ attacker-reachable content stays in the user slot.
2163
2370
 
2164
2371
  #### §packet-plugin-transform Trusted whole-list extension seam
2165
2372
 
@@ -2182,48 +2389,58 @@ grinding and folding remain closed engine concerns.
2182
2389
  Token accounting distinguishes the artifact being measured, the unit, and the
2183
2390
  time of measurement.
2184
2391
 
2185
- | Quantity | Source and unit | When | Contract |
2186
- |:-----------------------------------------------------------|:------------------------------------------------------------------|:--------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------|
2187
- | Provider usage | Provider-reported prompt/completion/reasoning tokens | After generation | Durable cost and transport forensics; never the pre-call packet budget. |
2188
- | Packet render-weight | `rulerCount = ceil(chars/2)` over rendered slots | Every packet build | Drives the Budget readout and grinder. |
2189
- | Stored content-depth | The same ruler over entry/log content | When content is written | Weights catalog and log rows without per-model workspace state. |
2190
- | §tokenomics-physical-admission Physical recovery admission | Provider measurement of the complete `PacketWire` message request | Only when the grinder cannot satisfy policy | Exact counts and proven upper bounds may authorize recovery. Estimates, unavailable evidence, and unknown provider physics fail closed. Never model-facing. |
2392
+ | Quantity | Source and unit | When | Contract |
2393
+ |:--------------------------------------------------------------------|:------------------------------------------------------------------|:------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
2394
+ | Provider usage | Provider-reported input/output tokens and cache/reasoning details | After each physical request | Durable monetary and transport forensics under {§provider-usage}; never the pre-call packet budget. |
2395
+ | Packet render-weight | `rulerCount = ceil(chars/2)` over rendered slots | Every packet build | Drives the Budget readout and grinder. |
2396
+ | Stored content-depth | The same ruler over entry/log content | When content is written | Weights catalog and log rows without per-model workspace state. |
2397
+ | §tokenomics-context-envelope-admission Hard context-envelope admission | Provider measurement of the complete `PacketWire` message request | After the grinder leaves negative ruler pressure | Exact counts and proven upper bounds may admit the request within the effective total envelope. Estimates and unknown capacity fail closed. Never model-facing. |
2191
2398
 
2192
2399
  - §tokenomics-tokens-stored-at-write **Ruler tokens, stored at write.** `entry_channels.tokens` and `log_entries.tokens` are populated with the model-independent `rulerCount` when their content is written. The stored number is a stable content-depth measurement, not a provider-specific prediction.
2193
2400
  - §tokenomics-render-weight-budget **Render-weight budget.** The budget headline — `ceiling`, `tokenUsage`, `tokensFree` — is the ruler measurement of the *assembled packet* after section transforms and budget substitution. Core measures minimum-width probes, monotonically expands fields that do not fit, then right-aligns the final values into those same widths; final substitution is length-invariant and displayed usage equals the stored request weight. A `SUM` of stored content-depth would measure different artifacts and cannot substitute for packet render-weight.
2194
2401
  - §tokenomics-context-percent **Prompt-budget percent.** The headline carries usage as a percent of the enforced model-facing budget — `usage Y (P%)` — beside the absolutes. It reads the ceiling already in hand; no extra provider call.
2195
- - §tokenomics-window-partition **Provider capacity and virtual pressure are
2196
- separate.** The provider owns physical context and generation settings. Core
2197
- derives the natural prompt capacity from that envelope and its packing-safety
2402
+ - §tokenomics-window-partition **Hard capacity and virtual pressure are
2403
+ separate.** The provider owns the effective total context envelope and
2404
+ generation settings. The envelope is already the minimum of model capacity
2405
+ and any stricter operator context cap ({§model-fact-resolution}); that cap is
2406
+ final. Core derives the natural prompt gauge from the envelope and its packing-safety
2198
2407
  margin. `PLURNK_SERVICE_PROMPT_BUDGET` is an optional alias-scoped virtual
2199
2408
  ceiling:
2200
2409
  `promptBudget = min(configuredPromptBudget, naturalPromptCapacity)`. Unset
2201
2410
  uses the natural capacity. The virtual ceiling controls only the packet gauge
2202
- and grinder; it never changes provider context, reasoning, completion, or
2411
+ and grinder; it never changes the hard context envelope, reasoning, completion, or
2203
2412
  `maxTokens`.
2413
+ - §tokenomics-prompt-projection-share **Prompt projection is stable packet policy.**
2414
+ `PLURNK_SERVICE_PROMPT_PROJECTION` is a required alias-scoped percentage in
2415
+ `(0, 100)`. It allocates that share of the enforced `promptBudget` to the
2416
+ aggregate automatic prompt-body projection. It does not bound stored prompt
2417
+ size, provider capacity, an explicit READ/FIND result, or the complete packet.
2418
+ Basing the share on the stable ceiling rather than current free weight keeps
2419
+ one prompt's projection byte-stable as the worker log evolves.
2204
2420
  - §tokenomics-window-unpollable-deliberate **Unknown provider capacity stays
2205
2421
  unknown.** Without a configured virtual ceiling, an unknown provider window
2206
2422
  leaves the prompt uncapped and omits denominator-dependent gauge telemetry. A
2207
- configured virtual ceiling still bounds PLURNK's packet without pretending
2208
- to describe provider physics. An over-policy recovery candidate cannot be
2209
- physically authorized without a known provider window and output envelope.
2423
+ configured virtual ceiling still supplies PLURNK's curation gauge without
2424
+ pretending to describe hard capacity. A negative-gauge request cannot be
2425
+ admitted without a known effective context and generation envelope.
2210
2426
 
2211
2427
  §tokenomics-client-gauge **The client gauge pairs current occupancy with its
2212
2428
  effective ceiling.** A model switch changes both latest-turn values together;
2213
- the loop-total usage fields remain billing evidence, not gauge inputs.
2429
+ the loop's aggregate provider accounting remains monetary evidence, not a gauge
2430
+ input.
2214
2431
 
2215
- | Surface | `contextTokens` | `promptBudget` |
2216
- | -------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
2217
- | `loop/terminated.usage` | Latest provider attempt on the latest turn; `0` when none completed | Latest turn's enforced packet allowance; `null` when uncapped or unknown |
2218
- | `providers.list` alias row | not present | Active alias's current enforced packet allowance; `null` when not established |
2432
+ | Surface | `contextTokens` | `promptBudget` |
2433
+ | -------------------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
2434
+ | `loop/terminated.usage` | `inputTokens` from the latest settled physical request on the latest turn; `null` when absent or unknown | Latest turn's enforced packet allowance; `null` when uncapped or unknown |
2435
+ | `providers.list` alias row | not present | Active alias's current enforced packet allowance; `null` when not established |
2219
2436
 
2220
2437
  - **Derivation is eager and exhaustive.** Workspace creation and searchable-resource changes start one coalesced warm. The first model turn joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or vector coverage. A semantic query ranks every eligible candidate in scope, so lexical overlap never gates vector recall. With no embedder, readable-content FTS is the explicit keyword fallback. Progress notices make the wait visible; latency is never hidden by partial semantics. {§derivation-exhaustive}
2221
2438
  - §membership-binary-sniff **Binary truth beats the label; no entry dominates the corpus.** A tracked member whose HEAD bytes contain NUL enters {§membership-source-projection} as `application/octet-stream` **regardless of what extension-based detection claims**; byte-level evidence outranks a default label. Every eligible text is tiled losslessly to the embedder window and every tile is embedded before its derivation attaches; semantic ranking max-pools the best chunk per candidate.
2222
- - §tokenomics-agnostic-ruler **One model-agnostic ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. The complete model-facing ledger therefore uses `rulerCount = ceil(chars/2)`: one content has one number regardless of which model reads it, with no per-model workspace state or recount pass. Under-policy packets rely on that ruler. Only an over-policy packet being considered for a recovery turn invokes the shipping provider's request-shaped physical measurement.
2223
- - §tokenomics-neutral-telemetry **Budget telemetry is state, not instruction.** The model-facing Budget is exactly one line: token ceiling, current usage and percentage, and free tokens. Per-entry weights remain on log rows where they describe the entries themselves. Packet-level composition, rankings, and visualizations are absent because their salience can redirect the model toward context gardening. OPEN/FOLD/KILL remain documented capabilities; recovery directs the model only after overflow. The model receives enough state to own its context decisions without a competing dashboard.
2439
+ - §tokenomics-agnostic-ruler **One model-agnostic ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. The complete model-facing ledger therefore uses `rulerCount = ceil(chars/2)`: one content has one number regardless of which model reads it, with no per-model workspace state or recount pass. Nonnegative-gauge packets rely on that ruler. Only a negative-gauge packet invokes the shipping provider's request-shaped hard-envelope measurement.
2440
+ - §tokenomics-neutral-telemetry **Budget telemetry is state, with one pressure alarm.** The model-facing Budget ordinarily has exactly one line: token ceiling, current usage and percentage, and free tokens. When free tokens are negative, exactly one second line reads `Context Token Budget Panic: YOU MUST FOLD or KILL enough less-relevant log items to restore free tokens.` Per-entry weights remain on log rows where they describe the entries themselves. Packet-level composition, rankings, and visualizations are absent. OPEN/FOLD/KILL remain the ordinary curation capabilities; no deterministic recovery process is prescribed.
2224
2441
  - §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as a stable per-content identity. `tokens` is stored in ruler units beside that content and is never keyed or recomputed by model.
2225
- - §tokenomics-provider-usage **Provider usage is transport and cost evidence, not curation state.** Every provider attempt preserves its validated `{§provider-cost}` evidence beside provider-reported prompt, completion, reasoning, and cached quantities. Turns and loops retain the ordered evidence. Their numeric USD projection is `null` if any included cost is unknown; free contributes zero, but unknown never does. Exact decimal evidence remains authoritative over the aggregate floating-point projection. Reasoning and completion are outputs the model cannot FOLD, so they never alter the model-facing Budget ledger.
2226
- - §tokenomics-over-budget-floor **The delivered packet is never over budget.** The readout shows the state of the packet the model actually has, and the grinder ({§grinder}) folds the newest turn boundary of an over-ceiling packet before it is sent. A delivered budget headline therefore always has usage <= ceiling, percent <= 100, and free >= 0. The percent describes the post-fold packet. If that one deterministic boundary fold cannot make the packet fit, the recovery/hard-413 contract applies; the engine never reaches backward and chooses older history to hide. The stored failure record renders an overshoot honestly - free floors at zero and percent may exceed 100 - but that record is never sent as an over-budget reasoning surface.
2442
+ - §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 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 logical 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` is an exact decimal string only when every request is expressible in USD and is `null` otherwise. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot FOLD, so they never alter the model-facing Budget ledger.
2443
+ - §tokenomics-negative-pressure **Negative ruler pressure is honest and nonterminal.** The readout describes the packet the model actually receives: usage and percent may exceed the virtual ceiling, and free tokens equal `ceiling - usage` without flooring. Crossing the ceiling records {§grinder-overflow-problem}, then the grinder ({§grinder}) folds only the newest boundary. If the rebuilt packet remains negative but exact or proven-bounded request evidence fits the effective hard envelope, generation proceeds under the ordinary operation contract. Overflow creates no strike or one-turn quota; only failed hard-envelope admission terminally rejects generation.
2227
2444
 
2228
2445
  ### §membership Workspace identity, membership, disk co-location
2229
2446
 
@@ -2264,15 +2481,15 @@ query is the absolute identity ({§scheme-address-network}); the sanitized
2264
2481
  readable projection is the fragmentless default, while faithful DOM, origin
2265
2482
  media type, and projection identity remain explicit auxiliary evidence. A
2266
2483
  normal
2267
- `READ(https://host/path?query)` therefore publishes only the sanitized body
2484
+ `## READ0 (https://host/path?query)` therefore publishes only the sanitized body
2268
2485
  under that exact URL—never raw HTML, response headers, or a channel-selection
2269
- lesson. FIND, matcher READ, and embeddings consume the same stored readable
2486
+ lesson. FIND and embeddings consume the same stored readable
2270
2487
  projection and never re-fetch each match. Because the search family is in
2271
2488
  `PLURNK_SERVICE_EXEC_HOLD`, the cycle holds until acquisition concludes
2272
2489
  ({§exec-hold-until-concluded}), so the next packet contains final
2273
2490
  materialization verdicts and folded ambient rows for every acquired page.
2274
2491
 
2275
- §search-gate Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin search→materialize→FIND/matcher READ and persistence/publication separation. Model web demos run the live composition end to end — real SearXNG, real pages; stubbed acquisition is confined to unit and integration seams and never appears in a demo. 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. **The search gates** are rail-family accounting — in-memory per-loop state cleaned at the same seam as strikes, restart-drop accepted (a post-restart duplicate re-fetches; the TTL makes it cheap): an IDENTICAL duplicate (same runtime + command in one loop) **strikes and serves** — status 409 (the strike rail counts the turn failure) carrying the prior ranked digest re-read live from the original exec entry, no re-fetch, no provenance prose; the per-turn CAP (`PLURNK_SERVICE_SEARCH_MAX_PER_TURN`) is flood control — 429 with a legible steer, nothing served.
2492
+ §search-gate Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin search→materialize→FIND and persistence/publication separation. Model web demos run the live composition end to end — real SearXNG, real pages; stubbed acquisition is confined to unit and integration seams and never appears in a demo. 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. **The search gates** are rail-family accounting — in-memory per-loop state cleaned at the same seam as strikes, restart-drop accepted (a post-restart duplicate re-fetches; the TTL makes it cheap): an IDENTICAL duplicate (same runtime + query in one loop) **strikes and serves** — status 409 (the strike rail counts the turn failure) carrying the prior ranked digest re-read live from the original exec entry, no re-fetch, no provenance prose; the per-turn CAP (`PLURNK_SERVICE_SEARCH_MAX_PER_TURN`) is flood control — 429 with a legible steer, nothing served.
2276
2493
 
2277
2494
  **Git is the substrate and the repository is the boundary:**
2278
2495
 
@@ -2296,7 +2513,8 @@ materialization verdicts and folded ambient rows for every acquired page.
2296
2513
  and directs the operator back to the default. The isomorphic untracked scan
2297
2514
  remains differential-gated against native
2298
2515
  `ls-files --others --exclude-standard`.
2299
- - §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** stays open — proposal→accept adds it to the manifest. Reaching past membership is `EXEC[sh]`'s job, not the file scheme's.
2516
+ - §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** stays open — proposal→accept adds it to the manifest. Reaching past membership is `## EXEC0 [sh]`'s job, not the file scheme's.
2517
+ - §membership-create-parents **Parent-complete creation.** An accepted File creation—whether authored as EDIT or as a COPY/MOVE destination—recursively creates missing parent directories before writing and registering the new member.
2300
2518
 
2301
2519
  **The overlay — `pick | view | hide`, removed by `drop`.** A `workspace_constraints` table is the client's supersede over Git. Resolved membership is `(project repository files ∪ pick) − hide`, with `view` enforced at the edit gate.
2302
2520
  - §membership-auto-add **Auto-add** — the project repository's membership is its tracked `ls-files` plus untracked-but-not-ignored files (`git ls-files --others --exclude-standard`), with `git` origin. A model-created file is a member the moment it exists—no `git add`—while `.gitignore` still filters it.
@@ -2318,7 +2536,13 @@ identity, and terminal disposition without exposing raw bytes or a base64 lane.
2318
2536
  | Binary with readable projection | Derived Unicode as `text/markdown` | READ uses the projection; source-aware EDIT remains 415. |
2319
2537
  | Binary without projection/over cap | Empty marker under the source binary mimetype | READ and EDIT return 415; private metadata distinguishes unavailable from limit. |
2320
2538
 
2321
- §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ body, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A resource attaches the immutable artifact only after it is complete; identical entry and log bodies therefore share one FTS row, one symbol graph, and one vector set without copying. 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. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every pending resource attaches a terminal classified artifact, identical at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
2539
+ §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ body, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A resource attaches the immutable artifact only after it is complete; identical entry and log bodies therefore share one FTS row, one symbol graph, and one vector set without copying. 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. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every resource completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
2540
+
2541
+ The artifact also retains a positive `{§mimetype-parse-issues}` count when the
2542
+ exact parsed body reported one. It remains advisory alongside a normally
2543
+ completed semantic disposition; zero and unavailable evidence persist as
2544
+ absence. Catalog projection attaches it only to that parsed body channel, never
2545
+ to sibling channels whose content the artifact does not describe.
2322
2546
 
2323
2547
  Every completed artifact records one terminal disposition: `vector`, `lexical`
2324
2548
  (only no embedder or an operator size ceiling), `excluded` (the configured
@@ -2338,11 +2562,11 @@ Lossless chunk admission requires either the embedder's own counter or an exact
2338
2562
 
2339
2563
  §semantic-max-embed-size **Embedding has an optional size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is an operator-set maximum UTF-8 byte size eligible for vectors; `0` is unlimited and is the shipped default. The measured value is the exact default body READ exposes and the embedder receives. Exhaustive embedding therefore remains the normal posture. When a nonzero ceiling rejects an oversized body, the entry remains directly readable with full graph and lexical indexing; only vectors are absent. The setting is folded into the deep derivation signature, so changing it honestly re-derives affected entries. Client notices report compact aggregate progress; the digest records every non-vector pathname, terminal disposition, and reason for forensic inspection.
2340
2564
 
2341
- §membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature is a stat-only no-op. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection}.
2565
+ §membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature is a stat-only no-op. The version token is either the observed `mtime:size` or the explicit `absent` state; an observed deletion removes the stale readable channels, and a later reappearance is therefore a new divergence rather than a first-sight materialization. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection}.
2342
2566
 
2343
2567
  §membership-emi-divergence-signal **EMI divergence signal.** The detector that gates the work *is* the one that fires this — one mechanism, not a second full read. When the change-detect finds a member moved out-of-band, the delta detector ({§env-delta}) surfaces it as a system `EDIT` log row naming the file, `source="file"` — the model sees what changed without diffing the manifest against memory. The model's own edits are write-through (the entry equals disk after a File write), so the scan never mis-attributes them as external divergence.
2344
2568
 
2345
- §membership-edit-write-cas **The write-back is a compare-and-swap — never a clobber, never a clever merge.** EDIT is *naive against the editable text snapshot*: it diffs the model's change onto the entry's body channel — the exact Unicode the model READ — and the proposal carries the `synced_sig` that snapshot was taken at. Binary sources are refused before this path ({§membership-source-projection}). At accept, `applyResolution` re-stats disk and lands the proposed content only if that signature still matches. If disk moved out-of-band in the propose→accept window — a sibling worker, the user's editor, a build step — the write is **refused** with a `write_conflict` and **nothing is written**. The engine neither blind-writes over the ambient change (a *clobber*) nor silently re-diffs the model's edit against a state it never saw (getting *clever*) — both would bury a stale-view contract violation under a fallback. The conflict surfaces instead: a ≥400 apply downgrades to a reject ({§proposal}), so the model sees the EDIT **did not occur** (400; the `write_conflict` outcome is forensics-only), the next reconcile narrates the real disk content as a `source=file` divergence ({§membership-emi-divergence-signal}), and the model re-reads and re-proposes against the fresh snapshot.
2569
+ §membership-edit-write-cas **The write-back is a compare-and-swap — never a clobber, never a clever merge.** EDIT is *naive against the editable text snapshot*: it diffs the model's change onto the entry's body channel — the exact Unicode the model READ — and the proposal carries the `synced_sig` that snapshot was taken at. Binary sources are refused before this path ({§membership-source-projection}). At accept, `applyResolution` re-stats disk and lands the proposed content only if that signature still matches. If disk moved out-of-band in the propose→accept window — a sibling worker, the user's editor, a build step — the write is **refused** with the same neutral `edit-collision` as {§edit-collision}, and **nothing is written**. The engine neither blind-writes over the ambient change (a *clobber*) nor silently re-diffs the model's edit against a state it never saw (getting *clever*) — both would bury a stale-view contract violation under a fallback. The collision surfaces instead: a ≥400 apply downgrades to a reject ({§proposal}), so the model sees that EDIT **did not occur** (400; the `edit_collision` outcome is forensics-only), the next reconcile narrates the real disk content as a `source=file` divergence ({§membership-emi-divergence-signal}), and the model re-reads and re-proposes against the fresh snapshot.
2346
2570
 
2347
2571
  The version travels *with the proposal*, never re-read from the entry at accept: a sibling worker in the same workspace may reconcile while this proposal sits paused, advancing the entry's `synced_sig` to the drifted disk — comparing against the *current* entry sig would wave that clobber through, so the comparison is always against the sig the proposal was computed at. A proposal that assumed an **absent** path (a create) conflicts only if a file has since appeared; a member with **no recorded snapshot** (an un-materialized entry, null `synced_sig`) has no baseline to guard and writes through — the two are told apart by the proposal's `existed` flag, not by a null sig alone. On a clean landing the entry refreshes to the written content and `synced_sig` is **restamped** to it, so the next reconcile recognizes the model's own write (not an external divergence) and a second same-turn edit bases on the landed bytes, not a stale sig. This is the write-side twin of the read-side change-gate ({§membership-change-gated-sync}): one `synced_sig`, gating both the re-read and the write.
2348
2572
 
@@ -2352,63 +2576,51 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
2352
2576
 
2353
2577
  **Rationale.** Workspace is the right scope unit and the containing Git repository is its ordinary development boundary. Membership curation is tiered: Git bounds it by tracking, the client supersedes by overlay, and the model curates its render by READ/FOLD. Supporting several independent repositories as one world would require Plurnk-owned topology, synchronization, and model teaching that Git already solves cleanly by treating them as separate workspaces.
2354
2578
 
2355
- **Schema.** The version-1 baseline stores provider attempts beneath turns.
2579
+ **Schema.** The version-1 baseline stores logical model calls beneath turns,
2580
+ emission admission as their specialization, and cardinal physical requests
2581
+ beneath each call. Its constraints distinguish pending calls, response
2582
+ evidence, and response-less errors while monetary classification remains
2583
+ explicit.
2356
2584
 
2357
2585
  ### §grinder Budget enforcement: the grinder
2358
2586
 
2359
- The grinder is the one pre-provider enforcement path for the model-facing prompt
2360
- ceiling. Its sequence is deterministic:
2587
+ The grinder is the one pre-provider curation path for the model-facing prompt
2588
+ gauge. Hard admission remains a separate predicate over the effective total
2589
+ context envelope:
2361
2590
 
2362
2591
  ```mermaid
2363
2592
  flowchart TD
2364
- assemble["Assemble and measure<br/>request packet"] --> policy{"Within policy ceiling?"}
2593
+ assemble["Assemble and measure<br/>request packet"] --> policy{"Nonnegative<br/>ruler gauge?"}
2365
2594
  policy -->|yes| unchanged["Provider generate<br/>packet unchanged"]
2366
- policy -->|no| fold["FOLD newest boundary<br/>tag overflow; mark budget strike"]
2595
+ policy -->|no| problem["Record nonterminal 413<br/>Token Budget Overflow"]
2596
+ problem --> fold["FOLD newest boundary<br/>and its OPEN effects<br/>tag overflow"]
2367
2597
  fold --> rebuild["Rebuild and remeasure"]
2368
- rebuild --> folded{"Within policy ceiling?"}
2369
- folded -->|yes| receipt["Record fold-to-fit Problem<br/>rebuild and remeasure"]
2370
- receipt --> finalPolicy{"Still within policy ceiling?"}
2371
- finalPolicy -->|yes| recovered["Provider generate<br/>with recovered packet"]
2372
- folded -->|no| candidate["Hard-recovery candidate"]
2373
- finalPolicy -->|no| candidate
2374
- candidate --> physical{"Candidate physically sendable?"}
2375
- physical -->|no| stop["413 hard stop<br/>no provider call"]
2376
- physical -->|yes| grant{"Recovery grant unused?"}
2377
- grant -->|no| stop
2378
- grant -->|yes| steer["Record recovery Problem<br/>allow PLAN / FOLD / KILL / SEND<br/>rebuild"]
2379
- steer --> finalPhysical{"Final packet physically sendable?"}
2380
- finalPhysical -->|yes| recovery["One constrained<br/>provider call"]
2381
- finalPhysical -->|no| stop
2598
+ rebuild --> folded{"Nonnegative<br/>ruler gauge?"}
2599
+ folded -->|yes| recovered["Provider generate<br/>with folded packet"]
2600
+ folded -->|no| admission{"Exact or bounded request<br/>fits hard envelope?"}
2601
+ admission -->|yes| pressured["Provider generate<br/>with negative Budget alarm"]
2602
+ admission -->|no / unknown / estimate| stop["413 hard stop<br/>no provider call"]
2382
2603
  ```
2383
2604
 
2384
2605
  §grinder-overflow-only **The grinder fires only on actual overflow.** In
2385
2606
  `Engine.runTurn`, after `PacketBuilder.buildRequestPacket` assembles the request
2386
2607
  and before `provider.generate`, it compares the packet's render-weight
2387
- ({§tokenomics}) with the policy ceiling. At or under the ceiling, the packet
2388
- ships untouched and the recovery grant clears. The grinder never trims
2608
+ ({§tokenomics}) with the virtual ceiling. At or under the ceiling, the packet
2609
+ ships untouched. The grinder never trims
2389
2610
  speculatively or "helpfully."
2390
2611
 
2391
- - §grinder-layer1-rollback **One rule, every turn: fold only the newest boundary.** The model owns context visibility. The grinder makes no relevance judgment and never reaches backward into older history. On overflow it folds, in one set operation, the still-open rows of the newest turn boundary: the immediately prior turn's emissions and the current turn's pre-model rows (foists and wake surfaces; every current-turn row at grind time is engine-written). Turn 1 follows the same rule: no prior turn exists, so its foists are the newest material. The same atomic set operation additively applies the `overflow` tag to every row it folds, so `OPEN[overflow]` can recall automatic curation through the ordinary log contract. Rows and bodies persist and remain re-OPENable.
2392
- - §grinder-errors-exempt **Errors, the prompt, AND the plan are exempt.** The grinder never folds an `op='error'` row (for example budget overflow or another engine rail): errors are the model's durable, curatable record of what went wrong. Nor does it fold the actionless **user prompt** row (`prompt:///<loop>/<N>`): the task frame is not ordinary model-authored memory. Nor a **PLAN row**: the checklist is the model's orientation surface when the grinder fires. All three stay OPEN until the model itself FOLDs or KILLs them.
2393
- - §grinder-hard-413-recovery **The hard overflow is a recovery turn first.** When the packet remains over the policy ceiling but the final recovery request has exact or proven-bounded evidence within the provider's physical window, it is sent once with exact `usage`, `ceiling`, and `deficit` measurements from overflow detection. The recovery turn physically admits only `PLAN`, `FOLD`, `KILL`, and `SEND`; every other authored op resolves 409 without executing. Its Problem directs the model to curate context by FOLDing or KILLing irrelevant log items without selecting those items for it. A next fitting turn clears the recovery state, and a later independent overflow can earn a new recovery. A recovery turn that concludes is a legitimate 200. The boundary is exactly 100% of the policy budget; provider decode capacity is reserved separately. The physical check applies after every row and section in the sent packet exists; only that final admission consumes the one recovery grant.
2394
- - §grinder-hard-413-abort **Hard stop.** A physically unsendable packet, or a second consecutive hard overflow after the constrained recovery turn, abandons the loop at **413 Content Too Large**. Its sibling engine-imposed terminals are HTTP-precise too: `maxTurns` -> 429 and a strike-out -> 500 (508 when cycle-driven). No catch-all 499 and no further passes.
2395
-
2396
- - §tokenomics-fetch-fits-free **A retrieval larger than the available packet room arrives folded.** The result lands in the next build; if that build exceeds the ceiling, the grinder folds the newest boundary, which contains the result. Its row and exact body remain durable and re-OPENable. If the packet still cannot fit, the recovery turn reports exact measurements and the allowed operation set. No ambient packet text prescribes an ordering strategy.
2612
+ - §grinder-overflow-problem **Token Budget Overflow is a nonterminal 413 Problem.** Every over-ceiling assembly records exactly one `engine/context/token-budget-overflow` Problem before automatic recovery, with pre-recovery `usage`, `ceiling`, and `deficit` evidence. Its exact `detail` is `Token Budget Overflow: Token Usage exceeded Token Ceiling. Newest log items were automatically FOLDed to fit within token budget. Curate the log and/or perform more conservatively scoped or chunked retrieval operations to recover.` The Problem remains durable and model-visible even when folding restores room and the turn later concludes successfully; it does not strike or replace the turn's terminal disposition.
2613
+ - §grinder-layer1-rollback **One rule, every turn: roll back context introduced by the newest boundary.** On overflow the grinder folds, in one set operation, still-open rows born in the immediately prior turn or current pre-model turn plus exact older rows that a successful OPEN in the immediately prior turn transitioned from folded to open. It reads those landed effects from {§fold-open-meta-operations}; it never re-runs the selector, treats an already-open target as newly introduced, or chooses other older history by relevance. Turn 1 has no prior turn, so only its pre-model rows qualify. The same set operation additively applies the `overflow` tag to every row it folds; rows and bodies remain re-OPENable.
2614
+ - §grinder-errors-exempt **Errors, the prompt, AND the plan are exempt.** The grinder never folds an `op='error'` row: errors are the model's durable, curatable record of what went wrong. Nor does it fold the actionless **user prompt** row (`prompt:///<loop>/<N>`): the task frame is not ordinary model-authored memory. Nor a **PLAN row**: the checklist is the model's orientation surface when the grinder fires. All three stay OPEN until the model itself FOLDs or KILLs them.
2615
+ - §grinder-hard-413 **The terminal hard stop belongs only to effective-envelope admission.** If the rebuilt packet remains ruler-negative, Core measures the complete `PacketWire` request and reserves the configured generation envelope. Exact or proven-bounded evidence within `provider.contextWindow` admits an ordinary turn regardless of ruler debt. Unknown capacity, an estimate, or evidence exceeding the effective prompt capacity abandons the loop immediately at **413 Content Too Large** without calling `provider.generate`. The terminal request stores one `engine/context/context-envelope-admission-failed` Problem with ruler pressure and admission evidence, distinct from the preceding nonterminal overflow 413; it is failure forensics, not a model recovery turn.
2397
2616
 
2398
- - §loop-terminals **Engine-imposed terminals are HTTP-precise** the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND[200]) · `499` model-abandoned (SEND[499], or a cancel) · `429` maxTurns exhausted · `413` budget hard-stop · `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` the bounded wait a loop blocked on a live obligation (the model's `SEND[202]<T,P>`, wait-obligation-matrix}); a wait on nothing resolves to `200` instead · `100`/`102` queued/running. Never a catch-all, never a new value without an owner schema ruling.
2617
+ - §tokenomics-fetch-fits-free **A retrieval larger than the available packet room arrives folded with a 413 explanation.** The result lands in the next build; if that build exceeds the ceiling, Core records {§grinder-overflow-problem} and folds the newest boundary, which contains the result. Its row and exact body remain durable and re-OPENable, and its `overflow` tag identifies every row selected by the automatic fold. Remaining ruler debt followstokenomics-negative-pressure}.
2399
2618
 
2400
- §grinder-strike-coupling **Strike coupling.** A grinder fire bumps the engine's
2401
- per-turn rail verdict, so an overflow contributes one strike under
2402
- {§engine-rails}. If cycle detection also fires on that turn, the turn still
2403
- contributes only one strike and a threshold crossing is classified as 508.
2619
+ - §loop-terminals **Engine-imposed terminals are HTTP-precise** the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND signal `200`) · `499` model-abandoned (signal `499`, or a cancel) · `429` maxTurns exhausted · `413` effective context-envelope admission failed · `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` the bounded wait — a loop blocked on a live obligation (the model's `## SEND0 [202] <T,P>`, {§wait-obligation-matrix}); a wait on nothing resolves to `200` unless a successful same-turn FOLD requires the curated next packet · `100`/`102` queued/running. Never a catch-all, never a new value without changing the owning schema.
2404
2620
 
2405
- §grinder-fold-strikes **Every grinder fold strikes, including turn 1.** There
2406
- is no soft exemption. Folded rows still cost their coordinate lines, so
2407
- repeated overflow can legitimately reach the strike threshold.
2621
+ §grinder-pressure-surface **What the model sees.** A fold-to-fit packet carries the open {§grinder-overflow-problem} row, its terse `## Errors` pointer, and ordinary folded rows whose complete sorted `tags` include `overflow`. If ruler pressure remains negative but hard admission succeeds, the Budget section also reports the negative free-token value and its one panic line ({§tokenomics-neutral-telemetry}). The 413 diagnoses the overflow without striking, terminalizing the turn, or changing the ordinary operation contract.
2408
2622
 
2409
- §grinder-overflow-error-row **What the model sees.** The overflow is an exact RFC 9457 Problem on an `op='error'` log row. Its stable type/title state the broken contract; `detail` and numeric extensions report Token Usage, Token Ceiling, and the positive deficit at the labeled `stage: "overflow-detection"` snapshot. When folding recovered the packet, the Problem also states that resolution and directs the model to keep irrelevant items folded or use smaller retrieval ranges; it never claims that no working room remains after the Budget section has measured a fitting rebuild. A hard recovery occurrence instead carries the enforced `allowedOperations` and its generally valid curation instruction. The packet rebuild that adds either Problem can make the neutral Budget section's current usage larger without contradicting the occurrence snapshot. The Problem is minted before the rebuild, so its derived `log:///<coord>` pointer surfaces in the errors section ({§operation-results}) on that turn. The strike counter stays engine-internal.
2410
-
2411
- The model controls its context; the engine enforces packet physics without
2623
+ The model controls its context; the engine enforces the hard envelope without
2412
2624
  choosing what older history matters. The same boundary applies on turn 1 and
2413
2625
  turn 101. The grinder folds reversibly, never deletes, and never performs
2414
2626
  speculative or non-overflow trimming.
@@ -2435,7 +2647,8 @@ flowchart LR
2435
2647
  pre-turn, a worker materializes every other actor's event on shared state after
2436
2648
  its last completed observation boundary into its own log. The set is
2437
2649
  exhaustive, unranked, and exactly once; the engine makes no relevance decision.
2438
- Each copied event retains its effect, cause, and typed attributes. Every
2650
+ Each copied event retains its effect, cause, typed attributes, and initial
2651
+ log classifications ({§log-item-tags}). Every
2439
2652
  producer appends to one workspace-scoped occurrence journal with a monotonic
2440
2653
  identity. A pull captures one closed `(worker cursor, high-water]` interval,
2441
2654
  materializes each identity idempotently, then advances the cursor only after the
@@ -2462,7 +2675,7 @@ cross this door, while an ancestry-authorized explicit READ remains available.
2462
2675
  | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
2463
2676
  | §env-delta-sibling-edit Sibling commons mutation | The sibling's successful resolved `EDIT` row and its receipt. | One folded `EDIT` retaining the exact effect and typed attributes. |
2464
2677
  | §env-delta-kernel-entry-edit Kernel-published mutation | The reserved `plurnk` worker's successful resolved `EDIT` row on `worker://plurnk/...`. | One folded `EDIT` retaining the published authority, exact effect, and typed attributes. |
2465
- | §env-delta-filesystem-narration Project-file divergence | The reserved `plurnk` worker records one `source=file` EDIT-shaped event during pre-turn membership reconciliation. | One folded `EDIT` naming the file and carrying the net changed span. No model operation is fabricated as having run. |
2678
+ | §env-delta-filesystem-narration Project-file divergence | The reserved `plurnk` worker records one `source=file` EDIT-shaped event during pre-turn membership reconciliation. | One folded `EDIT` naming the file and carrying the net changed span plus the exact two-coordinate Git porcelain status in `git` metadata when Git reports that path. No model operation is fabricated as having run. |
2466
2679
  | §env-delta-entry-materialization Executor `entry()` sink | The reserved `plurnk` worker records a typed `EDIT` event with `kind="entry_materialized"` and the calling worker as cause. | One folded system `READ` projection advertising newly readable state; the durable event remains an EDIT for replay and forensics ({§exec-entry-sink}). |
2467
2680
 
2468
2681
  §env-delta-attribution **Ownership, authorship, and cause are independent.**
@@ -2521,16 +2734,22 @@ the aggregate remains dispatch coordination state.
2521
2734
  | -------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
2522
2735
  | Full `revision` | `rev` abbreviated to `PLURNK_SERVICE_EDIT_RECEIPT_REVISION_CHARS` | SHA-256 identity of the complete landed channel body; display correlation only, never a lookup or compare-and-swap token. |
2523
2736
  | `unit`, `before`, `after` | `extent` | Whole-line batches use line counts. A batch containing any exact four-coordinate edit uses Unicode code-point counts. |
2737
+ | `parseIssues` | `parseIssues` | Positive parser-recovery count for the complete landed revision; clean, unsupported, and unavailable evidence is omitted. |
2524
2738
  | `effect.requested`, `source`, `result` | `range` | The admitted marker and its normalized mapping from the common source snapshot into the landed body. |
2525
2739
  | `effect.removed`, `inserted` | `change` | Removed and inserted counts in the receipt unit. |
2526
- | `effect.context` | Canonical row body | Numbered physical lines around the landed join, bounded by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
2740
+ | `effect.context` | Canonical row body | Numbered physical lines at each landed boundary, bounded symmetrically by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
2527
2741
  | `disposition`, `requested` | `disposition`, `requested` | A reviewer-replaced batch preserves the authored marker while stating that its attributed effect was superseded. |
2528
2742
  | `replacement` | `replacement`, `change`, canonical proposal-owner body | The one whole-resource effect actually applied by the reviewer replacement; never duplicated across authored rows. |
2529
2743
 
2530
2744
  §edit-result-receipt-truth **Receipts describe committed state.** Every row in
2531
- one resource-channel EDIT batch carries the same landed revision and extent.
2745
+ one resource-channel EDIT batch carries the same landed revision, extent, and
2746
+ optional positive `parseIssues` count for that complete revision.
2532
2747
  When the proposed batch lands unchanged, each row also carries its own requested
2533
- marker, source/result mapping, counts, and context.
2748
+ marker, source/result mapping, counts, and context. For configured count `C`,
2749
+ the context contains up to `C` surrounding lines and the first and last `C`
2750
+ landed lines at the result boundaries. Overlapping windows coalesce; coordinate
2751
+ jumps expose an omitted middle. A deletion instead shows up to `C` lines on
2752
+ each side of its join.
2534
2753
 
2535
2754
  §edit-result-reviewer-replacement **A resolver replacement is one effect, not a
2536
2755
  guess at authorship.** An arbitrary accepted body replaces the batch's proposed
@@ -2576,7 +2795,10 @@ landed.
2576
2795
  | `304`, rejection, or cancellation with no landed mutation | `effects` omitted. |
2577
2796
  | Cross-selection MOVE source failure after destination success | The failure retains every destination effect that landed. |
2578
2797
 
2579
- Core validates the complete ordered array before exposing it.
2798
+ Core validates the complete ordered array before exposing it. Parser-recovery
2799
+ inspection is advisory and occurs against complete resulting text after
2800
+ successful application. A handler or parser failure emits a Notice, omits
2801
+ `parseIssues`, and never changes the mutation outcome.
2580
2802
 
2581
2803
  ### §proposal-ownership Loop auto and client YOLO
2582
2804
 
@@ -2606,7 +2828,7 @@ when an emission is admitted, its response.** Core assembles and measures the
2606
2828
  request under {§packet-assembly}. An admitted response extends that same record
2607
2829
  before the turn closes; a failed provider call or exhausted invalid emission
2608
2830
  leaves the request-only record, while rejected exchanges remain in
2609
- `turn_attempts`.
2831
+ `model_calls` with their classification in `turn_attempts`.
2610
2832
 
2611
2833
  | Turn state | `turns.packet` |
2612
2834
  | ----------------------------- | ----------------------------------------------- |
@@ -2654,7 +2876,7 @@ by service policy.
2654
2876
  |--------------------------------|----------------|
2655
2877
  | `worker` / `loop` / `turn` | The process hierarchy in {§lifecycle-terms}; unqualified `run` names no internal entity. |
2656
2878
  | `packet` | The assembled address space, a kernel concept rather than merely a provider request. |
2657
- | `costUsd` | No standard cost field exists; the explicit currency avoids implied units. |
2879
+ | `costUsd` | No standard cost field exists; the explicit currency avoids implied units, and the value remains an exact decimal string. |
2658
2880
  | `PLURNK_SERVICE_SAFETY` | The ruler's packing margin is a service fact no provider owns. |
2659
2881
  | the `chars/2` ruler | Model-agnostic by design ({§tokenomics-agnostic-ruler}). |
2660
2882
 
@@ -2662,26 +2884,31 @@ Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualifie
2662
2884
 
2663
2885
  §encrypted-reasoning-carrier **Encrypted reasoning is opaque client evidence.**
2664
2886
  When a provider returns encrypted reasoning items, core attaches that list to
2665
- the admitted model mirror row's `attrs.reasoning`. `log/entry` and `readLog`
2887
+ the admitted model-emission row's `attrs.reasoning`. `log/entry` and `readLog`
2666
2888
  carry it to AG-UI, which may project correlated standard reasoning entities.
2667
2889
  Core never decodes the blobs or renders them into a model packet; readable
2668
2890
  reasoning text remains separate in `assistant.reasoning`. The provider-detail
2669
2891
  identity and derived classification retain their exact provider-normalized
2670
2892
  meaning from {§provider-encrypted-reasoning}; core never reinterprets either as
2671
- a client entity. The mirror row and provider attempt remain the lossless
2893
+ a client entity. The mirror row and logical model call remain the lossless
2672
2894
  evidence when a downstream standard cannot represent the complete list.
2673
2895
 
2674
2896
  §body-projection **One full body, one packet projection.** Every durable log row has one canonical full body resolved from its stored tx/rx envelope by `LogBody`. READ and FIND over `log:///`, persistent search derivation, and packet rendering all consume that same meaning. Only packet rendering may project it:
2675
2897
 
2676
2898
  | row producer | ordinary OPEN projection |
2677
2899
  |---|---|
2678
- | model-origin `READ` or `FIND` | complete result explicitly retrieved by the model |
2900
+ | any `READ` or `FIND` | complete selected operation result |
2901
+ | any `PLAN` | complete authored working memory |
2902
+ | actionless lowercase `prompt` | budgeted head under {§prompt-projection} |
2903
+ | structured `EDIT` receipt or textual `COPY`/`MOVE` effects | complete receipt-owned join context |
2679
2904
  | every other nonempty body | head bounded independently by `PLURNK_SERVICE_PREVIEW_LINES` and `PLURNK_SERVICE_PREVIEW_CHARS` |
2680
2905
  | bodyless row | `"display":"none","body":""` |
2681
2906
 
2682
- The exemption is provenance plus operation, not the overloaded operation label: an engine-pushed stream delta shaped as READ remains bounded. Prompts, model mirrors, PLAN/SEND/WORK/FORK bodies, EXEC commands, mutation receipts, ambient deltas, and extension-produced bodies cannot create a second preview policy. A bounded row carries the exact `overflow` message defined by {§jsonplurnk} and names its own `log:///` address. `READ(log:///<coordinate>/<op>)` returns the canonical full body and then applies the authored matcher/range; `FIND(log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores it without bypassing the bound. System/policy sections are not log bodies. Notices are transient non-log observations; they share the line/character bounds but have no durable body or recovery URI.
2907
+ READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. PLAN is likewise complete while OPEN: it is the model's explicit persistent reasoning inventory, not ordinary content that the model should have to retrieve from itself. 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. Model-emission mirrors, SEND/WORK/FORK bodies, EXEC commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. When an OPEN projection differs from its canonical body, `chunk` follows the displayed `body` with the exact selected and complete extents defined by {§jsonplurnk}; complete and FOLDED bodies omit it. `## READ0 (log:///<coordinate>/<OP>)` applies its default or explicit text range to the canonical body; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. `## FIND0 (log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores the producer's projection without changing its bound. 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.
2908
+
2909
+ §prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt:///<loop>/<N>` as an owner-keyed text/markdown entry, then published to its turn as one actionless lowercase `prompt` log row. No synthetic EDIT or READ operation is invented. The row is born OPEN and obeys {§body-projection}. The **Active User Prompts** section closes the user-slot status clump as a paths-only list (`* prompt:///<loop>/<N>`), so every frame remains directly READable even after its log row is folded or killed.
2683
2910
 
2684
- §prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt:///<loop>/<N>` as an owner-keyed text/markdown entry, then published to its turn as one actionless lowercase `prompt` log row. No synthetic EDIT or READ operation is invented. The row is born OPEN and obeys {§body-projection}. The **User Prompts** section closes the user-slot status clump as a paths-only list (`* prompt:///<loop>/<N>`), so every frame remains directly READable even after its log row is folded or killed.
2911
+ §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 enforced `promptBudget` and the alias-resolved percentage from `PLURNK_SERVICE_PROMPT_PROJECTION` derive one aggregate ruler-weight allowance for OPEN prompt bodies. Complete prompt bodies render when their aggregate weight fits. Otherwise all OPEN 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` after `body`; the canonical `prompt:///` entry and `log:///` body remain complete and READ/FIND-addressable. Without an enforced packet ceiling 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.
2685
2912
 
2686
2913
  §prompt-self-only The frame is self-only and owner-keyed:
2687
2914
  `entries.owner_id` carries worker identity while the address carries only the
@@ -2701,13 +2928,13 @@ contract.
2701
2928
  §packet-catalog **Catalogs are query results, not packet state.** The packet
2702
2929
  stores no materialized manifest. Complete and one-level entry directories,
2703
2930
  their row shape, and their ordering are ordinary FIND projections owned by
2704
- {§find-result-catalog-rows}; persistent search derivation is a separate index.
2931
+ {§find-result-projection}; persistent search derivation is a separate index.
2705
2932
 
2706
2933
  ### §operation-results Model-facing failures and notices
2707
2934
 
2708
2935
  The model's runtime alert surface has two distinct kinds of information:
2709
2936
 
2710
- - **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content and remain exclusively in `turn_attempts`.
2937
+ - **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery mirror under {§invalid-emission-attempts}.
2711
2938
  - **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `embed_progress`, and `grammar_unenforced` may appear once in the packet and broadcast live. They neither substitute for a failure result nor influence scheduling or recovery.
2712
2939
 
2713
2940
  The `log` is durable product truth. The `errors` section points at its failures
@@ -2744,7 +2971,7 @@ retain distinct contracts and lifetimes.
2744
2971
  | failure | row | status |
2745
2972
  |---|---|---|
2746
2973
  | action failure | the failed op's own row; the owning scheme supplies Problem Details | 4xx/5xx |
2747
- | budget overflow | `op='error'`, source `rail` or `engine`; `engine/grinder/budget-overflow` Problem Details | 413 |
2974
+ | context-envelope admission | `op='error'`, origin `plurnk`, source `engine`; `engine/context/context-envelope-admission-failed` Problem Details | 413 |
2748
2975
  | max commands exceeded | `op='error'`, origin `plurnk`, source `rail`; `engine/rail/max-commands-exceeded` Problem Details | 429 |
2749
2976
  | idle turn | `op='error'`, origin `plurnk`, source `rail`; `engine/rail/idle-turn` Problem Details | 409 |
2750
2977
 
@@ -2757,7 +2984,7 @@ retain distinct contracts and lifetimes.
2757
2984
 
2758
2985
  §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.
2759
2986
 
2760
- §operation-result-no-error-scheme Private strike and cycle accounting stays engine-internal ({§rail-accounting-private}). Every failure within an accepted turn - a bounded parse error, failed action, or engine rail - is a LOG ITEM (`log:///<coord>`, `status_rx ≥ 400`) with Problem Details, foldable and re-OPENable. The `errors` section surfaces a derived pointer to each. Rejected provider attempts stay in the forensic attempt relation. There is **no bespoke `error://` scheme** and no ephemeral per-category failure buffer.
2987
+ §operation-result-no-error-scheme Private strike and cycle accounting stays engine-internal ({§rail-accounting-private}). Every failure within an accepted turn - a bounded parse error, failed action, or engine rail - is a LOG ITEM (`log:///<coord>`, `status_rx ≥ 400`) with Problem Details, foldable and re-OPENable. The `errors` section surfaces a derived pointer to each. Rejected emissions stay in the forensic model-call and admission relations. There is **no bespoke `error://` scheme** and no ephemeral per-category failure buffer.
2761
2988
 
2762
2989
  §notice-event-notify **Client surface.** Engine Notices broadcast live via the `notice/event` WS notification — `{ loopId, notice: { source, kind, level, message?, position?, …kind-specific } }` per the grammar's `Notice` schema — the moment they land, scoped to the loop's workspace. AG-UI projects the same observation as the custom `plurnk.notice` event. Failures do not broadcast on this surface: they are log rows, and the client reads them through `log.read` / the `log/entry` notification, the durable log.
2763
2990
 
@@ -2768,10 +2995,10 @@ retain distinct contracts and lifetimes.
2768
2995
  | Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its co-located `digest.sql`; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
2769
2996
  | `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
2770
2997
  | `digestDir` | Selects the output directory. `run` removes and recreates it so stale packet artifacts cannot survive; concurrent callers use distinct directories. |
2771
- | `workerId` | Narrows workers and every dependent loop, turn, attempt, log row, and rollup to that one worker. |
2998
+ | `workerId` | Narrows workers and every dependent loop, turn, logical model call, emission attempt, physical request, and log row to that one worker. |
2772
2999
  | `workspaceId` | Narrows workers and dependent evidence to one workspace; when both selectors are present they intersect. |
2773
3000
 
2774
- §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log row, including causal `source` and structured `attrs`, the exact Problem on every failed row, and each loop's exact terminal result. 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 folded network-entry storage paths 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; packet files remain byte-identical records of what the model saw.
3001
+ §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log row, including causal `source` and structured `attrs`, every exact OPEN/FOLD target effect from {§fold-open-meta-operations}, the exact Problem on every failed row, each loop's exact terminal result, and every ordered physical provider request. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. 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 folded network-entry storage paths 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; packet files remain byte-identical records of what the model saw.
2775
3002
 
2776
3003
  §digest-requiem **A requiem is an out-of-band forensic interview, not a worker
2777
3004
  turn.** It cannot execute operations or alter the audited history.
@@ -2779,11 +3006,11 @@ turn.** It cannot execute operations or alter the audited history.
2779
3006
  | Aspect | Contract |
2780
3007
  |-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
2781
3008
  | Scope | One interview for each worker with model-bearing turns; journal-only workers are omitted. |
2782
- | Evidence | The worker's final packet plus every admitted and rejected provider attempt from its history. |
3009
+ | Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. |
2783
3010
  | Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
2784
- | Identity | The worker's durable id is sent as both `workerId` and `primaryWorkerId`, making the synthetic interview its own root without asserting a live worker topology. |
3011
+ | 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. |
2785
3012
  | 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`. |
2786
- | Artifacts | `requiem.md` carries testimony and authoritative usage/cost totals; `requiem.json` preserves exact messages, responses, usage, and provider-calculated cost. |
3013
+ | 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. |
2787
3014
 
2788
3015
  §turn-lifecycle **Turn-lifecycle liveness.** Provider generation is the long, opaque window in a turn — one or more same-packet emission attempts may occur before the first committed op. A static client screen there is indistinguishable from a hang. The engine brackets the complete attempt window with two `notice/event` notices (`source: "engine:turn"`, `level: "info"`): `turn_awaiting_model` before the first call and `turn_generated` when an emission is accepted or the attempt budget is exhausted. Rejected content never rides the notice channel. Both are suppressed on an aborted loop and broadcast to the workspace like any notice ({§notice-event-notify}).
2789
3016
 
@@ -2791,28 +3018,28 @@ turn.** It cannot execute operations or alter the audited history.
2791
3018
 
2792
3019
  ### §tools user.tools — the capability sheet
2793
3020
 
2794
- §tools-capability-sheet The executable-tools capability sheet renders under `## Registered Executable Tools`, directly after the `definition` (plurnk.md) section and **above** `## Recap`. The heading defines the fenced examples as the closed set of valid executor selectors, not suggestions for an open-ended `[tag]` convention. Optional non-EXEC operations render separately under `## Enabled Optional Operations`, so the executable catalogue remains truthful. Both use `plurnk` fences — one packet, one shape for operation-example sheets — assembled by `PacketBuilder.#collectTools`; a prose notice (e.g. the EXEC-disabled line) stays beside the executor fence, and empty sections are omitted.
3021
+ §tools-capability-sheet The tools capability sheet renders under `## Registered Tools`, after the policy sections. One generated Markdown table is the closed set of valid executor selectors and states each runtime declaration's model-facing `(target)` role, body role, and exact canonical example. The compact legend leaves required inputs unmarked, marks optional inputs with `?`, pairs mutually exclusive alternatives with `↔`, marks refused buckets with `—`, and locates optional `<timeout,poll>` on the heading. The preface prefers purpose-built Plurnk operations over EXEC scripts. For a declaration with `target.directory: "cwd"`, the target cell distinguishes a local-directory working context from the plugin-authored non-directory target role. Optional non-EXEC operations render separately under `## Enabled Optional Operations` in a `plurnk` fence, so the catalogue remains truthful. `PacketBuilder.#collectTools` assembles both; a prose notice (e.g. the EXEC-disabled line) stays beside the table, and empty sections are omitted.
2795
3022
 
2796
3023
  §tools-loop-affinity **The capability sheet describes the current loop.** The
2797
3024
  sheet filters registered capabilities through the same
2798
3025
  `SchemeRegistry.resolveForLoop(flags)` predicate the dispatcher enforces. When
2799
- registered executors exist but EXEC is inactive, their examples are replaced by
3026
+ registered executors exist but EXEC is inactive, their table is replaced by
2800
3027
  an explicit disabled notice rather than silent absence. The dispatch 403 remains
2801
3028
  the backstop and names the non-retryable loop restriction.
2802
3029
 
2803
- **Contributors: the wired executor tags.** Each available executor tag *with an example* contributes ONE bare op — its canonical usage — into the `plurnk` fence (identical shape to the scheme directory, schemes}); its doc is materialized at `worker://plurnk/docs/<tag>.md` and discovered via the turn-0 `FIND(worker://plurnk/docs/**)` foist, not linked inline. A tag with no example contributes nothing; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named tag's line + doc. The boot `ExecutorRegistry` probes availability per tag, so the catalogue advertises runnable selectors instead of presuming a particular runtime exists.
3030
+ **Contributors: the wired executor tags.** Every available executor tag contributes exactly one row derived from its requiredexecutor-invocation} declaration. Its doc is materialized at `worker://plurnk/docs/<tag>.md` and discovered via the turn-0 `## FIND0 [+init,+docs] (worker://plurnk/docs/**)` foist, not linked inline. `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named tag's row and doc. The boot `ExecutorRegistry` probes availability per tag, so the table advertises runnable selectors instead of presuming a particular runtime exists.
2804
3031
 
2805
- ### §schemes user.schemes — the scheme directory
3032
+ ### §schemes user.schemes — the resource directory
2806
3033
 
2807
- §schemes-directory A `## Schemes` section renders in the system slot **after the definition (plurnk.md — grammar + imperatives) and the tools sheet** — a terse directory of the scheme families available this workspace, so the model knows what URI schemes exist before it acts. Each scheme that ships a `manifest.example` contributes ONE bare op its canonical usage (no scheme prefix; the example self-documents) into a `plurnk` fence ({§tools} shares the shape). The doc is NOT linked inline — it is materialized at `worker://plurnk/docs/<scheme>.md` and discovered via the turn-0 `FIND(worker://plurnk/docs/**)` foist, keeping the raw packet free of doc links. Meta-owned `log` and `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls, the examples fenced like the tools sheet ({§tools}). A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's line + doc.
3034
+ §schemes-directory A `## Resources` section renders in the system slot **after the policy sections and tools sheet** — a terse directory of the scheme families available this workspace, so the model knows what URI resources and operations exist before it acts. Each scheme that ships a `manifest.example` contributes one or more concise canonical ops (no scheme prefix; each example self-documents) into a `plurnk` fence. Scheme example sets are separated by one blank line. The doc is NOT linked inline — it is materialized at `worker://plurnk/docs/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+docs] (worker://plurnk/docs/**)` foist, keeping the raw packet free of doc links. Meta-owned `log` and `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls. A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's examples + doc.
2808
3035
 
2809
3036
  ### §inject system.inject — the operator injection
2810
3037
 
2811
- §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot **right after the teaching** (definition → toolsschemes → inject), ahead of the policy sections part of the cached prefix. Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard (a deliberate setting with a broken path is a misconfig, surfaced not hidden). `~/` expands to home. It's the operator-side complement to the plugin section hook — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
3038
+ §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot after policy and capability teaching (definition → policyproject policy tools resources inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard (a deliberate setting with a broken path is a misconfig, surfaced not hidden). `~/` expands to home. It's the operator-side complement to the plugin section hook — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
2812
3039
 
2813
3040
  ### §policy system.policy — the client's policy injection
2814
3041
 
2815
- §policy-sections Two sections ride the system slot **below the operator notes, at the slot's bottom**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `~/.plurnk/AGENTS.md`) and `## Project Policy` from `PLURNK_SERVICE_PROJECT` (default `<projectRoot>/AGENTS.md`, resolved relative to the workspace root). AGENTS.md is **policy** — the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. 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. Reference and scratch docs are NOT policy; `PLURNK_SERVICE_MD_*` materializes them as READ-able entries ({§operator-config}).
3042
+ §policy-sections Two sections ride the system slot **after the definition and before loop-dependent capabilities**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `~/.plurnk/AGENTS.md`) and `## Project Policy` from `PLURNK_SERVICE_PROJECT` (default `<projectRoot>/AGENTS.md`, resolved relative to the workspace root). AGENTS.md is **policy** — the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. 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. Reference and scratch docs are NOT policy; `PLURNK_SERVICE_MD_*` materializes them as READ-able entries ({§operator-config}).
2816
3043
 
2817
3044
  On first run, and only when `~/.plurnk` itself is absent, the service seeds
2818
3045
  `AGENTS.md` from `@plurnk/plurnk-meta/PLURNK_PERSONALITY.md` ({§teaching-corpus}).
@@ -2821,27 +3048,29 @@ surfaces with its cause and leaves no apparently initialized home.
2821
3048
  After that bootstrap the file is user-owned: edits and deletion persist, and a
2822
3049
  later boot never refreshes or recreates it.
2823
3050
 
2824
- §schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path one-liner and the latter is the deep pull doc. `SchemeRegistry.teach()` renders the directory, `SchemeRegistry.docs()` resolves corpus-or-manifest documentation, and `docEntries()` materializes the result when core publishes capabilities for a workspace.
2825
-
2826
- ### §requirements The requirements section — static per-turn rules
3051
+ §schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path operation example set and the latter is the deep pull doc. `SchemeRegistry.teach()` renders the directory, `SchemeRegistry.docs()` resolves corpus-or-manifest documentation, and `docEntries()` materializes the result when core publishes capabilities for a workspace.
2827
3052
 
2828
- - §requirements-requirements-render-last Rendered at the end of the user packet
2829
- under `## Recap`, closest to the assistant turn so the contract the model has
2830
- to honor is the most recent text it sees.
2831
- - §requirements-requirements-omitted-when-empty The header is omitted entirely
2832
- when the requirements string is empty.
3053
+ ### §packet-git-status The Git status section compact repository state
2833
3054
 
2834
- Contains a compact, recency-biased recap of operational law already owned by
2835
- `plurnk.md`: the op shape, one complete turn, and the SEND[200] completion
2836
- condition. This duplication is deliberate; it is the user-slot footer closest
2837
- to generation, not a second contract. PLAN remains mandated by `plurnk.md`
2838
- "Imperatives", so the service injects no additional plan directive.
3055
+ When Git is admitted for the workspace, `## Git Status` reports the current
3056
+ branch, upstream ahead/behind counts, and staged/unstaged/untracked totals. The
3057
+ active direct child of a running branch batch additionally receives its assigned
3058
+ branch and the requirement to commit any project changes and leave the checkout
3059
+ clean before concluding ({§worker-branch-batch-return}); no other worker receives
3060
+ that instruction. The section never repeats an unbounded path list. Per-path state belongs to
3061
+ the durable causal observation: a `source=file` environment-delta row carries
3062
+ the exact two-character porcelain `XY` value as `git` metadata when the status
3063
+ snapshot names that path. The engine takes one snapshot after membership
3064
+ reconciliation and uses it for both projections; no per-file Git process exists.
2839
3065
 
2840
- **Sourcing:** a non-empty `runLoop({ requirements })` / `runTurn({ requirements })` value overrides the default. Otherwise `Paths.defaultRequirements` resolves `PLURNK_SERVICE_REQUIREMENTS` or the required `@plurnk/plurnk-meta/requirements.md` source ({§teaching-corpus}). The engine reads that file for every packet; a failed read fails the build with its cause, and requirements are not persisted or cascaded through the database.
3066
+ ### §requirements Recap footer
2841
3067
 
2842
- **Rationale:** the user's prompt is natural language ("Reply with just the number") and routinely conflicts with the grammar's operational contract. Without an explicit requirement block, the model obeys the prompt literally and never reaches for SEND. Requirements are the contract that wins those conflicts.
2843
-
2844
- ---
3068
+ The user slot ends with `## Recap`, a compact recency-biased reminder of selected
3069
+ operational law already owned by `plurnk.md`. A non-empty `runLoop` / `runTurn`
3070
+ `requirements` value overrides the default; otherwise core reads
3071
+ `PLURNK_SERVICE_REQUIREMENTS` or the required meta-owned `requirements.md` source
3072
+ for every packet. A failed read fails packet assembly with its cause. The footer
3073
+ is one projection path and one authored source, not a second language contract.
2845
3074
 
2846
3075
  ## §matcher Matcher selection and text regions
2847
3076
 
@@ -2867,7 +3096,7 @@ stored a resource.
2867
3096
  §graph-relations **Graph matching is one-hop, kind-agnostic name matching.**
2868
3097
  Source definitions resolve over the complete relationship universe (the
2869
3098
  workspace for entry FIND; the worker's complete log for log FIND), while the
2870
- authored target and tags still constrain every resource returned. Outgoing
3099
+ authored target still constrains every resource returned. Outgoing
2871
3100
  references belong to a definition through the handler-reported fully qualified
2872
3101
  container identity.
2873
3102
 
@@ -2902,12 +3131,11 @@ Glob anchoring (`TODO*` starts-with, `*TODO*` contains, `*.log` ends-with,
2902
3131
 
2903
3132
  §matcher-result-resource-selection **A matcher selects resources; it never extracts a value or chooses a retrieval
2904
3133
  window.** Every dialect answers whether a resource matches and may return
2905
- `MatchEvidence { path?, region? }` ({§matcher-selection-signal}). `path` is a
3134
+ `MatchEvidence { locator?, region? }` ({§matcher-selection-signal}). `locator` is a
2906
3135
  canonical structural locator. `region` is a complete `TextRegion` in the exact
2907
3136
  text the model can READ and may be exact or the smallest honest enclosing
2908
- region. A matcher miss is 204. FIND lists a selected resource
2909
- once; READ returns it once, complete unless the authored READ supplied a text
2910
- scope.
3137
+ region. A matcher miss is 204. FIND's target shape projects the selected
3138
+ resources according to {§find-result-projection}.
2911
3139
 
2912
3140
  | Dialect | Selects | Natural use |
2913
3141
  |---|---|---|
@@ -2918,15 +3146,12 @@ scope.
2918
3146
  | `~`semantic `~q` | resources ranked by indexed chunks | chunk text region when available |
2919
3147
  | `@`graph `@<sym` | resources with matching symbol relations | symbol text region when available |
2920
3148
 
2921
- §read-multi-file-fanout **READ uses the FIND contract as a selector, not as a visible intermediate operation.** A READ over a glob, folder, relation matcher, or acquisition-scheme matcher writes one READ log row per selected resource. It does not write a synthetic FIND row. Every matcher delivery carries all of that resource's match evidence. A body-less folder/glob uses the same resource unit. An exact stored-resource content matcher may resolve directly with the same visible contract, preserving content-level outcomes such as the 203 raw-source fallback. A bare body-less entry remains one direct READ. Zero selections write one 204 row. If selection exceeds {§find-count-not-contents}, READ writes one 413 refusal and no hidden deliveries. Fan-out checks cancellation between resources.
2922
-
2923
- **Selection and projection are ordered and independent.** The matcher evaluates
2924
- the complete readable candidate. The READ marker then projects text from each
2925
- selected resource. Match evidence is never an implicit projection: it gives the
2926
- model enough information to author a surgical follow-up READ without the engine
2927
- guessing which occurrence or context window it wants. A locator-only or
2928
- coordinate-less valid result still selects the resource; the service never
2929
- fabricates coordinates. {§read-selection-projection}
3149
+ Match evidence is navigation evidence, never an implicit body projection. The
3150
+ model uses broad FIND to select and page resources, exact FIND to page that
3151
+ resource's locations, then explicit exact READs—parallel in one turn when
3152
+ useful—to retrieve chosen bodies or regions. A locator-only or coordinate-less
3153
+ valid result still selects the resource; the service never fabricates
3154
+ coordinates. {§read-exact-target} {§read-selection-projection}
2930
3155
 
2931
3156
  ### §text-scope-runtime Text-scope runtime projection
2932
3157
 
@@ -2953,7 +3178,7 @@ coordinates, inverted regions, out-of-range coordinates, and other arities are
2953
3178
  416.
2954
3179
 
2955
3180
  Every successful scoped READ carries its complete resolved `region` in the
2956
- operation result and packet metadata. The body remains line-numbered from
3181
+ operation result and packet metadata. The body remains coordinate-prefixed from
2957
3182
  `startLine`; the region preserves columns that line numbering cannot express.
2958
3183
 
2959
3184
  Every same-resource mutation resolves its replacement offsets against one
@@ -2963,7 +3188,7 @@ SARIF region/replacement algebra for exact spans and same-snapshot ordering, not
2963
3188
  adoption of the SARIF interchange envelope.
2964
3189
 
2965
3190
  §slice-semantics-compose-pattern **Compose from evidence.** A match region already uses the four-coordinate
2966
- scope shape. A follow-up `READ(resource)<SL,SC,EL,EC>` retrieves that exact
3191
+ scope shape. A follow-up `## READ0 (resource) <SL,SC,EL,EC>` retrieves that exact
2967
3192
  region. JSONPath/XPath remain locators and matchers; they do not introduce a
2968
3193
  second structural scope or structural EDIT language.
2969
3194
 
@@ -2984,15 +3209,18 @@ projection, and binary handling. Text scope meaning does not vary by mimetype.
2984
3209
 
2985
3210
  ### §render-rule Render rule
2986
3211
 
2987
- §render-rule-line-navigable-prefix Every textual content body with a source `startLine` renders with an `N:`
2988
- prefix on each physical line, independent of mimetype. JSON, XML, and HTML are
2989
- therefore just as line-addressable as markdown and source code. The prefix is a
2990
- packet presentation aid, never part of canonical content; matchers and
2991
- mutations consume canonical bytes before rendering. A producer may set
2992
- `startLine: null` only when its content is already source-numbered, such as an
2993
- effect receipt.
3212
+ §render-rule-line-navigable-prefix Every textual content body with a source
3213
+ `startLine` renders with a coordinate prefix on each physical line, independent
3214
+ of mimetype. A successful exact READ whose active scheme declares
3215
+ `textEditScopes: true` and model write authority supplies `@hash N:` with one
3216
+ or more ASCII spaces before `N` under
3217
+ {§line-anchors}; every other body renders `N:`. JSON, XML, and HTML are therefore just as
3218
+ line-addressable as markdown and source code. The prefix is a packet
3219
+ presentation aid, never part of canonical content; matchers and mutations
3220
+ consume canonical bytes before rendering. A producer may set `startLine: null`
3221
+ only when its content is already source-numbered, such as an effect receipt.
2994
3222
 
2995
- §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND/model/prompt and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; EXEC and the composed PLAN/SEND/WORK/FORK family use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and universal line numbering. READ/FIND over `log:///` and search consume the complete canonical body instead. 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.
3223
+ §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, model-emission, prompt, and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; EXEC and the composed PLAN/SEND/WORK/FORK family 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 consume the complete canonical body instead. 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.
2996
3224
 
2997
3225
  An `EDIT` log row renders its bounded effect receipt (`rx.receipt`) as row
2998
3226
  metadata and join context, not its input statement. Proposal-gated file EDITs
@@ -3003,7 +3231,8 @@ any scoped textual receipt contexts under their `log:///` address, never under
3003
3231
  one operand's resource address. All generated bodies remain under
3004
3232
  {§body-projection}. {§edit-result-render}
3005
3233
 
3006
- The `N:` prefix is presentation/reference per plurnk.md ("not part of the source"); stripped before any matcher operation on the log entry.
3234
+ Numeric and anchored coordinate prefixes are presentation/reference per
3235
+ plurnk.md ("not part of the source"); matchers operate on canonical content.
3007
3236
 
3008
3237
  ### §markdown-primitive Mimetype primitive: text/markdown
3009
3238
 
@@ -3023,10 +3252,14 @@ Carried from the contract walk; durable.
3023
3252
  - **Binary markers** → 415 for text operations. A readable binary source is durably represented as projected `text/markdown` under {§membership-source-projection}; source-aware File EDIT remains 415.
3024
3253
  - **EDIT `<L>` on non-existent entry** → body becomes content; `<L>` is positional-only on existing content.
3025
3254
  - §copy-l-source-range **COPY/MOVE source scope** selects only the addressed source channel and
3026
- transfers canonical text without the packet's `N:` prefix. A MOVE removes
3255
+ first resolves and, when required, prepares the same canonical
3256
+ owner-addressed representation as exact READ/FIND. It transfers canonical
3257
+ text without the packet's coordinate prefix. A MOVE removes
3027
3258
  that same selected region; an unscoped MOVE removes only the selected
3028
3259
  channel, deleting the entry only when no channels remain. A binary marker
3029
- is not transferable; a readable binary projection is already a textual channel.
3260
+ is not transferable; a readable binary projection is already a textual
3261
+ channel. A selected producer failure aborts before destination mutation;
3262
+ successful non-`200` content remains transferable.
3030
3263
 
3031
3264
  - **COPY/MOVE destination scope** is independent of the source scope and lowers
3032
3265
  through the destination scheme's `editBatch`.
@@ -3035,10 +3268,11 @@ Carried from the contract walk; durable.
3035
3268
  Any scoped textual transfer materializes create/update receipts; whole-channel
3036
3269
  changes do not. Operand selections remain independently visible per
3037
3270
  {§copy-move-observation}.
3038
- - **READ rx** prefixes every textual line with `N:` per {§render-rule}.
3039
- - **FIND body matcher** applies to entry content (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). Scope + tags select candidates in SQL; the path-glob is the (target).
3271
+ - **READ rx** prefixes every textual line under {§render-rule}; eligible
3272
+ editable resources carry `@hash N:`, and all others carry `N:`.
3273
+ - **FIND body matcher** applies to entry content (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). The target scope selects candidates; the path-glob is the (target). FIND's signal classifies its own log item ({§log-item-tags}).
3040
3274
  - **OPEN/FOLD** operate on the **log** (`log:///`), not entries ({§open-fold}) — FOLD collapses a log row to its path, OPEN restores its body. Aimed at an entry scheme they return 501.
3041
- - **SEND[410]** deletes as a side-effect (not the model idiom; {§move}): with `#fragment`, that channel only; without, the whole entry. **SEND[499]** resolves the durable open-subscription row and invokes that subscription's exact callable owner through the process-local live registry ({§subscriptions}).
3275
+ - **SEND signal `410`** deletes as a side-effect (not the model idiom; {§move}): with `#fragment`, that channel only; without, the whole entry. **SEND signal `499`** resolves the durable open-subscription row and invokes that subscription's exact callable owner through the process-local live registry ({§subscriptions}).
3042
3276
  - **File scheme** detects with `Mimetypes.detect({ path })` and classifies with the same configured service ({§mimetype-classification-consumption}). Handler-declared binary sources materialize through {§membership-source-projection}; projected bodies are READ-able, while source-aware EDIT remains 415.
3043
3277
 
3044
3278
  ### §send-status-policy Directed-SEND status code policy