@plurnk/plurnk-service 1.10.1 → 1.12.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 (314) hide show
  1. package/.env.defaults +41 -17
  2. package/INSTALL.md +4 -4
  3. package/README.md +2 -2
  4. package/SPEC.md +573 -273
  5. package/digest-sql/curation/curation.sql +1 -0
  6. package/dist/Paths.d.ts +3 -3
  7. package/dist/Paths.d.ts.map +1 -1
  8. package/dist/Paths.js +9 -9
  9. package/dist/Paths.js.map +1 -1
  10. package/dist/build-info.json +1 -1
  11. package/dist/content/edit-collision.d.ts +1 -1
  12. package/dist/content/edit-collision.d.ts.map +1 -1
  13. package/dist/content/edit-collision.js +5 -4
  14. package/dist/content/edit-collision.js.map +1 -1
  15. package/dist/content/edit-receipt.d.ts +6 -5
  16. package/dist/content/edit-receipt.d.ts.map +1 -1
  17. package/dist/content/edit-receipt.js +28 -8
  18. package/dist/content/edit-receipt.js.map +1 -1
  19. package/dist/content/index.d.ts +2 -2
  20. package/dist/content/index.d.ts.map +1 -1
  21. package/dist/content/index.js +1 -1
  22. package/dist/content/index.js.map +1 -1
  23. package/dist/content/line-anchors.d.ts +2 -0
  24. package/dist/content/line-anchors.d.ts.map +1 -1
  25. package/dist/content/line-anchors.js +15 -6
  26. package/dist/content/line-anchors.js.map +1 -1
  27. package/dist/content/line-marker.d.ts +0 -1
  28. package/dist/content/line-marker.d.ts.map +1 -1
  29. package/dist/content/line-marker.js.map +1 -1
  30. package/dist/content/matcher.d.ts.map +1 -1
  31. package/dist/content/matcher.js +3 -2
  32. package/dist/content/matcher.js.map +1 -1
  33. package/dist/content/read-projector.js +3 -3
  34. package/dist/content/read-projector.js.map +1 -1
  35. package/dist/core/BudgetReadout.d.ts +6 -1
  36. package/dist/core/BudgetReadout.d.ts.map +1 -1
  37. package/dist/core/BudgetReadout.js +38 -2
  38. package/dist/core/BudgetReadout.js.map +1 -1
  39. package/dist/core/CapabilityPolicies.d.ts +15 -0
  40. package/dist/core/CapabilityPolicies.d.ts.map +1 -0
  41. package/dist/core/CapabilityPolicies.js +60 -0
  42. package/dist/core/CapabilityPolicies.js.map +1 -0
  43. package/dist/core/CapabilityResolver.d.ts +24 -0
  44. package/dist/core/CapabilityResolver.d.ts.map +1 -0
  45. package/dist/core/CapabilityResolver.js +180 -0
  46. package/dist/core/CapabilityResolver.js.map +1 -0
  47. package/dist/core/ChannelWrite.d.ts +4 -3
  48. package/dist/core/ChannelWrite.d.ts.map +1 -1
  49. package/dist/core/CoreSchemeServices.d.ts +2 -2
  50. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  51. package/dist/core/CoreSchemeServices.js +2 -2
  52. package/dist/core/CoreSchemeServices.js.map +1 -1
  53. package/dist/core/Dispatcher.d.ts +5 -2
  54. package/dist/core/Dispatcher.d.ts.map +1 -1
  55. package/dist/core/Dispatcher.js +157 -165
  56. package/dist/core/Dispatcher.js.map +1 -1
  57. package/dist/core/DurableStatement.d.ts.map +1 -1
  58. package/dist/core/DurableStatement.js +19 -15
  59. package/dist/core/DurableStatement.js.map +1 -1
  60. package/dist/core/EmbeddingCall.d.ts +23 -0
  61. package/dist/core/EmbeddingCall.d.ts.map +1 -0
  62. package/dist/core/EmbeddingCall.js +149 -0
  63. package/dist/core/EmbeddingCall.js.map +1 -0
  64. package/dist/core/Engine.d.ts +6 -4
  65. package/dist/core/Engine.d.ts.map +1 -1
  66. package/dist/core/Engine.js +20 -9
  67. package/dist/core/Engine.js.map +1 -1
  68. package/dist/core/Engine.sql +119 -56
  69. package/dist/core/ExecutorRegistry.d.ts +3 -3
  70. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  71. package/dist/core/ExecutorRegistry.js +10 -6
  72. package/dist/core/ExecutorRegistry.js.map +1 -1
  73. package/dist/core/GitBranch.d.ts +4 -1
  74. package/dist/core/GitBranch.d.ts.map +1 -1
  75. package/dist/core/GitBranch.js +12 -2
  76. package/dist/core/GitBranch.js.map +1 -1
  77. package/dist/core/InferenceCall.d.ts +18 -0
  78. package/dist/core/InferenceCall.d.ts.map +1 -0
  79. package/dist/core/InferenceCall.js +86 -0
  80. package/dist/core/InferenceCall.js.map +1 -0
  81. package/dist/core/LogEntryProjection.d.ts +1 -0
  82. package/dist/core/LogEntryProjection.d.ts.map +1 -1
  83. package/dist/core/LogEntryProjection.js +12 -4
  84. package/dist/core/LogEntryProjection.js.map +1 -1
  85. package/dist/core/LoopPolicyReader.d.ts +7 -0
  86. package/dist/core/LoopPolicyReader.d.ts.map +1 -0
  87. package/dist/core/LoopPolicyReader.js +33 -0
  88. package/dist/core/LoopPolicyReader.js.map +1 -0
  89. package/dist/core/ModelCall.d.ts +4 -12
  90. package/dist/core/ModelCall.d.ts.map +1 -1
  91. package/dist/core/ModelCall.js +10 -74
  92. package/dist/core/ModelCall.js.map +1 -1
  93. package/dist/core/NoticeChannel.d.ts +2 -2
  94. package/dist/core/NoticeChannel.d.ts.map +1 -1
  95. package/dist/core/NoticeChannel.js +18 -9
  96. package/dist/core/NoticeChannel.js.map +1 -1
  97. package/dist/core/OperatorConfig.d.ts.map +1 -1
  98. package/dist/core/OperatorConfig.js +4 -0
  99. package/dist/core/OperatorConfig.js.map +1 -1
  100. package/dist/core/OverflowTurn.d.ts.map +1 -1
  101. package/dist/core/OverflowTurn.js +4 -3
  102. package/dist/core/OverflowTurn.js.map +1 -1
  103. package/dist/core/Owner.js +5 -5
  104. package/dist/core/Owner.js.map +1 -1
  105. package/dist/core/PacketBuilder.d.ts +2 -2
  106. package/dist/core/PacketBuilder.d.ts.map +1 -1
  107. package/dist/core/PacketBuilder.js +55 -35
  108. package/dist/core/PacketBuilder.js.map +1 -1
  109. package/dist/core/ProblemLog.d.ts.map +1 -1
  110. package/dist/core/ProblemLog.js +1 -0
  111. package/dist/core/ProblemLog.js.map +1 -1
  112. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  113. package/dist/core/ProposalLifecycle.js +16 -13
  114. package/dist/core/ProposalLifecycle.js.map +1 -1
  115. package/dist/core/ReasoningEvent.d.ts +1 -0
  116. package/dist/core/ReasoningEvent.d.ts.map +1 -1
  117. package/dist/core/ResourceMutations.d.ts +6 -4
  118. package/dist/core/ResourceMutations.d.ts.map +1 -1
  119. package/dist/core/ResourceMutations.js +209 -63
  120. package/dist/core/ResourceMutations.js.map +1 -1
  121. package/dist/core/SchemeRegistry.d.ts +6 -3
  122. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  123. package/dist/core/SchemeRegistry.js +14 -17
  124. package/dist/core/SchemeRegistry.js.map +1 -1
  125. package/dist/core/ServiceTeardown.d.ts +1 -1
  126. package/dist/core/ServiceTeardown.d.ts.map +1 -1
  127. package/dist/core/ServiceTeardown.js +4 -8
  128. package/dist/core/ServiceTeardown.js.map +1 -1
  129. package/dist/core/StrikeRail.d.ts +1 -0
  130. package/dist/core/StrikeRail.d.ts.map +1 -1
  131. package/dist/core/StrikeRail.js +12 -3
  132. package/dist/core/StrikeRail.js.map +1 -1
  133. package/dist/core/ToolResources.d.ts +2 -2
  134. package/dist/core/ToolResources.d.ts.map +1 -1
  135. package/dist/core/ToolResources.js +18 -8
  136. package/dist/core/ToolResources.js.map +1 -1
  137. package/dist/core/Turn.sql +6 -3
  138. package/dist/core/TurnOps.d.ts.map +1 -1
  139. package/dist/core/TurnOps.js +22 -8
  140. package/dist/core/TurnOps.js.map +1 -1
  141. package/dist/core/TurnRunner.d.ts +7 -4
  142. package/dist/core/TurnRunner.d.ts.map +1 -1
  143. package/dist/core/TurnRunner.js +345 -83
  144. package/dist/core/TurnRunner.js.map +1 -1
  145. package/dist/core/WorkerControlAddress.d.ts.map +1 -1
  146. package/dist/core/WorkerControlAddress.js +1 -2
  147. package/dist/core/WorkerControlAddress.js.map +1 -1
  148. package/dist/core/WorkerName.d.ts +2 -0
  149. package/dist/core/WorkerName.d.ts.map +1 -1
  150. package/dist/core/WorkerName.js +3 -2
  151. package/dist/core/WorkerName.js.map +1 -1
  152. package/dist/core/WorkerName.sql +2 -1
  153. package/dist/core/caps/DbProjectionCaps.d.ts +2 -1
  154. package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
  155. package/dist/core/caps/DbProjectionCaps.js +12 -1
  156. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  157. package/dist/core/file-materialization.d.ts +22 -0
  158. package/dist/core/file-materialization.d.ts.map +1 -0
  159. package/dist/core/file-materialization.js +77 -0
  160. package/dist/core/file-materialization.js.map +1 -0
  161. package/dist/core/fork.d.ts +2 -1
  162. package/dist/core/fork.d.ts.map +1 -1
  163. package/dist/core/fork.js +13 -4
  164. package/dist/core/fork.js.map +1 -1
  165. package/dist/core/fork.sql +27 -11
  166. package/dist/core/git-membership.d.ts +25 -14
  167. package/dist/core/git-membership.d.ts.map +1 -1
  168. package/dist/core/git-membership.js +260 -164
  169. package/dist/core/git-membership.js.map +1 -1
  170. package/dist/core/git-state.d.ts +2 -0
  171. package/dist/core/git-state.d.ts.map +1 -1
  172. package/dist/core/git-state.js +27 -1
  173. package/dist/core/git-state.js.map +1 -1
  174. package/dist/core/operation-target-groups.d.ts.map +1 -1
  175. package/dist/core/operation-target-groups.js +8 -7
  176. package/dist/core/operation-target-groups.js.map +1 -1
  177. package/dist/core/owner.sql +7 -10
  178. package/dist/core/packet-wire.d.ts +11 -0
  179. package/dist/core/packet-wire.d.ts.map +1 -1
  180. package/dist/core/packet-wire.js +98 -34
  181. package/dist/core/packet-wire.js.map +1 -1
  182. package/dist/core/scheme-types.d.ts +2 -2
  183. package/dist/core/scheme-types.d.ts.map +1 -1
  184. package/dist/core/scheme-types.js +1 -1
  185. package/dist/core/scheme-types.js.map +1 -1
  186. package/dist/core/types.d.ts +3 -2
  187. package/dist/core/types.d.ts.map +1 -1
  188. package/dist/core/types.js +1 -1
  189. package/dist/core/types.js.map +1 -1
  190. package/dist/core/worker-settings.d.ts +4 -3
  191. package/dist/core/worker-settings.d.ts.map +1 -1
  192. package/dist/core/worker-settings.js +40 -19
  193. package/dist/core/worker-settings.js.map +1 -1
  194. package/dist/core/workspace-settings.d.ts +3 -1
  195. package/dist/core/workspace-settings.d.ts.map +1 -1
  196. package/dist/core/workspace-settings.js +6 -2
  197. package/dist/core/workspace-settings.js.map +1 -1
  198. package/dist/digest/Digest.d.ts.map +1 -1
  199. package/dist/digest/Digest.js +151 -42
  200. package/dist/digest/Digest.js.map +1 -1
  201. package/dist/digest/digest.sql +48 -20
  202. package/dist/index.js +1 -1
  203. package/dist/index.js.map +1 -1
  204. package/dist/schemes/Exec.d.ts +4 -5
  205. package/dist/schemes/Exec.d.ts.map +1 -1
  206. package/dist/schemes/Exec.js +111 -94
  207. package/dist/schemes/Exec.js.map +1 -1
  208. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  209. package/dist/schemes/ExecOutputScheme.js +24 -6
  210. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  211. package/dist/schemes/ExecScheduler.d.ts +15 -0
  212. package/dist/schemes/ExecScheduler.d.ts.map +1 -0
  213. package/dist/schemes/ExecScheduler.js +95 -0
  214. package/dist/schemes/ExecScheduler.js.map +1 -0
  215. package/dist/schemes/File.d.ts.map +1 -1
  216. package/dist/schemes/File.js +26 -19
  217. package/dist/schemes/File.js.map +1 -1
  218. package/dist/schemes/Log.d.ts +6 -4
  219. package/dist/schemes/Log.d.ts.map +1 -1
  220. package/dist/schemes/Log.js +132 -39
  221. package/dist/schemes/Log.js.map +1 -1
  222. package/dist/schemes/Log.sql +23 -18
  223. package/dist/schemes/QuestionTool.d.ts +17 -4
  224. package/dist/schemes/QuestionTool.d.ts.map +1 -1
  225. package/dist/schemes/QuestionTool.js +2 -4
  226. package/dist/schemes/QuestionTool.js.map +1 -1
  227. package/dist/schemes/Worker.d.ts.map +1 -1
  228. package/dist/schemes/Worker.js +20 -20
  229. package/dist/schemes/Worker.js.map +1 -1
  230. package/dist/schemes/_entry-chunk.d.ts.map +1 -1
  231. package/dist/schemes/_entry-chunk.js +6 -2
  232. package/dist/schemes/_entry-chunk.js.map +1 -1
  233. package/dist/schemes/_entry-crud.sql +18 -17
  234. package/dist/schemes/_entry-find.d.ts.map +1 -1
  235. package/dist/schemes/_entry-find.js +9 -14
  236. package/dist/schemes/_entry-find.js.map +1 -1
  237. package/dist/schemes/_entry-graph.js +12 -12
  238. package/dist/schemes/_entry-graph.js.map +1 -1
  239. package/dist/schemes/_entry-graph.sql +5 -5
  240. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  241. package/dist/schemes/_entry-ops.js +15 -5
  242. package/dist/schemes/_entry-ops.js.map +1 -1
  243. package/dist/schemes/_entry-semantic.d.ts +5 -3
  244. package/dist/schemes/_entry-semantic.d.ts.map +1 -1
  245. package/dist/schemes/_entry-semantic.js +21 -9
  246. package/dist/schemes/_entry-semantic.js.map +1 -1
  247. package/dist/schemes/_path-scope.d.ts.map +1 -1
  248. package/dist/schemes/_path-scope.js +6 -1
  249. package/dist/schemes/_path-scope.js.map +1 -1
  250. package/dist/schemes/_search-index.d.ts.map +1 -1
  251. package/dist/schemes/_search-index.js +14 -2
  252. package/dist/schemes/_search-index.js.map +1 -1
  253. package/dist/server/BranchBatches.d.ts +3 -3
  254. package/dist/server/BranchBatches.d.ts.map +1 -1
  255. package/dist/server/BranchBatches.js +9 -2
  256. package/dist/server/BranchBatches.js.map +1 -1
  257. package/dist/server/Daemon.d.ts +12 -41
  258. package/dist/server/Daemon.d.ts.map +1 -1
  259. package/dist/server/Daemon.js +60 -93
  260. package/dist/server/Daemon.js.map +1 -1
  261. package/dist/server/DaemonModule.d.ts +10 -1
  262. package/dist/server/DaemonModule.d.ts.map +1 -1
  263. package/dist/server/DrainSupervisor.d.ts +6 -5
  264. package/dist/server/DrainSupervisor.d.ts.map +1 -1
  265. package/dist/server/DrainSupervisor.js +14 -11
  266. package/dist/server/DrainSupervisor.js.map +1 -1
  267. package/dist/server/Functionality.d.ts +2 -2
  268. package/dist/server/Functionality.d.ts.map +1 -1
  269. package/dist/server/Functionality.js +8 -5
  270. package/dist/server/Functionality.js.map +1 -1
  271. package/dist/server/FunctionalityManager.d.ts +13 -1
  272. package/dist/server/FunctionalityManager.d.ts.map +1 -1
  273. package/dist/server/FunctionalityManager.js +82 -17
  274. package/dist/server/FunctionalityManager.js.map +1 -1
  275. package/dist/server/MembersFunctionality.d.ts +56 -0
  276. package/dist/server/MembersFunctionality.d.ts.map +1 -0
  277. package/dist/server/MembersFunctionality.js +350 -0
  278. package/dist/server/MembersFunctionality.js.map +1 -0
  279. package/dist/server/SkillsFunctionality.d.ts +12 -1
  280. package/dist/server/SkillsFunctionality.d.ts.map +1 -1
  281. package/dist/server/SkillsFunctionality.js +6 -1
  282. package/dist/server/SkillsFunctionality.js.map +1 -1
  283. package/dist/server/client-input.d.ts +5 -8
  284. package/dist/server/client-input.d.ts.map +1 -1
  285. package/dist/server/client-input.js +49 -108
  286. package/dist/server/client-input.js.map +1 -1
  287. package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
  288. package/dist/server/dispatch-as-plurnk.js +3 -0
  289. package/dist/server/dispatch-as-plurnk.js.map +1 -1
  290. package/dist/server/drain.sql +4 -4
  291. package/dist/server/envelope.d.ts +1 -1
  292. package/dist/server/envelope.d.ts.map +1 -1
  293. package/dist/server/envelope.js +11 -10
  294. package/dist/server/envelope.js.map +1 -1
  295. package/dist/server/envelope.sql +1 -1
  296. package/dist/server/lifecycle-recovery.sql +14 -20
  297. package/dist/server/loopDocs.d.ts.map +1 -1
  298. package/dist/server/loopDocs.js +12 -5
  299. package/dist/server/loopDocs.js.map +1 -1
  300. package/dist/server/seam-proposal-list.sql +2 -2
  301. package/dist/server/worker-capabilities.sql +9 -0
  302. package/dist/service.d.ts.map +1 -1
  303. package/dist/service.js +18 -23
  304. package/dist/service.js.map +1 -1
  305. package/migrations/001_schema.sql +477 -131
  306. package/package.json +31 -33
  307. package/dist/core/LoopFlagsReader.d.ts +0 -7
  308. package/dist/core/LoopFlagsReader.d.ts.map +0 -1
  309. package/dist/core/LoopFlagsReader.js +0 -33
  310. package/dist/core/LoopFlagsReader.js.map +0 -1
  311. package/dist/core/resolveForLoop.d.ts +0 -5
  312. package/dist/core/resolveForLoop.d.ts.map +0 -1
  313. package/dist/core/resolveForLoop.js +0 -12
  314. package/dist/core/resolveForLoop.js.map +0 -1
package/SPEC.md CHANGED
@@ -50,7 +50,7 @@ their absence never makes a client, plugin, or `_plurnk` turn exceptional.
50
50
  | `kind` | Required purpose: `inference`, `initialization`, `overflow`, `operation`, or `maintenance`. Model iff inference; initialization, overflow, and maintenance require `_plurnk`. A maintenance turn's successful rows are packet-suppressed — a receipt answers an asker, and maintenance has none ({§actor-boundary-doc-injection}). |
51
51
  | `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the exact terminal SEND/operation disposition and timestamp; a completed 102 is therefore distinct from an open 102. |
52
52
  | Operations | Ordered by `(turn_id, sequence)` on one exact worker/loop/turn chain. Each row's `origin` is the turn producer or `_plurnk` making a system observation; the observation does not impersonate the producer. |
53
- | `turnOps` | Every admitted source-backed turn preserves its exact PLAN…SEND program as one undecorated actionless log item under {§turn-ops-entry}. The item supplements rather than replaces the executed operation rows. |
53
+ | `turnOps` | Every admitted source-backed turn preserves its exact PLAN…SEND program as one actionless `/ops` log item under {§turn-ops-entry}. The item supplements rather than replaces the executed operation rows. |
54
54
  | Inference evidence | Model calls, `packet`, model, finish reason, and provider metadata belong only to model/inference turns. Turn fields are nullable until recorded and remain NULL for every other kind. |
55
55
 
56
56
  One lifecycle owner opens, optionally records inference evidence, and completes
@@ -117,6 +117,25 @@ These are the complete strike sources:
117
117
  executor error is not a PLURNK contract violation. Cycle and terminal steering
118
118
  remain independent strike sources.
119
119
 
120
+ §provider-recovery **A recoverable provider failure never ends a loop.** When a model
121
+ call fails with a network failure, rate limit, deadline, or interrupted resource after
122
+ the provider's own retries, the turn records the exact Problem as a `_plurnk` row,
123
+ notices the client (`engine:provider` / `provider_unavailable`), waits with
124
+ exponential backoff (`PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF`, doubling, capped at
125
+ twelve times itself), and re-issues the same call against the exact frozen model
126
+ messages whose response is still outstanding. Each reissue remains a distinct logical
127
+ model call with complete physical-request accounting, but the active turn's newly
128
+ recorded provider Problems do not recursively enter that request; they surface normally
129
+ only in a later genuinely new packet. No emission attempt is consumed and no strike is
130
+ scored. Every recovery checkpoint broadcasts live, while the model-facing Notice buffer
131
+ retains only the current provider state; the next completed exchange notices
132
+ `provider_recovered`. Recovery is bounded by `PLURNK_SERVICE_PROVIDER_RECOVERY`; when it
133
+ is spent the turn completes as `202` and the loop parks exactly like a
134
+ `## SEND0 [202]` wait ({§worker-lifecycle-wake-requeue-not-terminal}), resuming on the
135
+ next prompt or wake with its log intact. Only a client cancel, the loop deadline
136
+ ({§operator-config-loop-timeout}), or a non-recoverable provider Problem (refusal,
137
+ authorization, quota, an invalid response) settles a loop on a provider failure.
138
+
120
139
  A struck turn increments the consecutive streak once; a clean admitted turn
121
140
  resets it to zero. Reaching `MAX_STRIKES` terminates at **508 Loop Detected**
122
141
  when the crossing turn is cycle-detected, otherwise **500**. Rejected emission
@@ -130,11 +149,11 @@ shown. The current streak may ride first-party provider metadata
130
149
  |------------------------------|---|
131
150
  | **verdict** | The end-of-turn ruling computed inline in `Engine.runLoop` from the strike rail and independent loop terminals. No filter chain. |
132
151
  | **strike** | One admitted turn matching at least one source above. |
133
- | **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. |
152
+ | **emission attempt** | One completed provider exchange beneath an engine turn. ANTLR admits it when at least one source operation has a trustworthy effective envelope and no boundary-destroying tail. A hard error inside that envelope becomes a failed operation in the admitted turn; a rejected attempt is forensic evidence, not another turn or an engine strike. |
134
153
  | **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}). |
135
154
  | **cycle** | A repeated turn fingerprint across consecutive turns. Detection strikes silently under the rule above. |
136
- | §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. |
137
- | **flag** | Per-loop value: `mode`, `noWeb`, and `noInteraction` shape scheme authority ({§manifest-flag-affinity}); `auto` and `noProposals` select proposal settlement. |
155
+ | **capability policy** | A purely subtractive `only`/`deny` selector layer over routed operation demands. Service, workspace, inherited delegation bound, worker, and loop layers compose without granting authority. |
156
+ | **loop policy** | One immutable loop snapshot containing capability attenuation and the independent `review`, `accept`, or `reject` proposal disposition. |
138
157
  | **proposal** | A deferred side-effecting action. State machine: `proposed → resolved` (accept), `→ failed` (reject), or `→ cancelled` (cancel). Its core-owned disposition says whether the client or loop owns resolution ({§proposal-disposition}). |
139
158
  | **resolution** | A client decision delivered through a standard resume entry. Proposal resolutions accept, reject, or cancel ({§methods-proposal-resolve}); client-interaction resolutions return a payload or cancel ({§methods-client-interaction-resolve}, {§agui-proposal-resolve}). |
140
159
 
@@ -282,18 +301,28 @@ an explicitly specified subpath, not in the frozen root barrel.
282
301
 
283
302
  ```mermaid
284
303
  flowchart LR
285
- DB["Acquire daemon lock<br/>and admit SQLite schema"] --> PROVIDER["Resolve and verify<br/>selected provider"]
304
+ LISTENER["Bind client listener<br/>unready: HTTP 503"] --> DB["Acquire daemon lock<br/>and admit SQLite schema"]
305
+ DB --> PROVIDER["Resolve and verify<br/>selected provider"]
286
306
  PROVIDER --> DAEMON["Construct and start<br/>daemon composition"]
287
- DAEMON --> CLIENT["Open client transport"]
288
- DB -. failure .-> FAIL["Fail startup"]
307
+ DAEMON --> CLIENT["Activate client transport"]
308
+ LISTENER -. failure .-> FAIL["Fail startup<br/>durable state untouched"]
309
+ DB -. failure .-> CLOSE_LISTENER["Close listener"] --> FAIL
289
310
  PROVIDER -. failure .-> CLOSE["Close database<br/>and release lock"] --> FAIL
290
311
  DAEMON -. failure .-> TEARDOWN["Close every started owner"] --> FAIL
291
312
  ```
292
313
 
293
- §startup-admission-order Database admission completes before provider or
294
- capability initialization can perform external work. Every later startup
295
- failure closes the resources already admitted in reverse ownership order while
296
- preserving the originating failure.
314
+ §startup-listener-admission The production service binds its sole client
315
+ listener before creating, opening, replacing, rotating, migrating, or otherwise
316
+ mutating anything in the durable data directory. A process that loses the
317
+ listener race fails with the originating address error and byte-identical
318
+ durable storage. The client-interface module owns the socket continuously; it
319
+ answers 503 until activated, so early ownership introduces neither traffic nor a
320
+ close/rebind race.
321
+
322
+ §startup-admission-order After listener ownership, database admission completes
323
+ before provider or capability initialization can perform external work. Every
324
+ later startup failure closes resources in reverse ownership order while
325
+ preserving the originating failure: daemon, observability, database, listener.
297
326
 
298
327
  ### §actor-boundary The actor boundary: isolation by worker, two doors, self-hosting
299
328
 
@@ -321,8 +350,8 @@ filter a row.
321
350
  attached to.** A client connection is attached to one conversation Worker; its
322
351
  management commands mutate that Worker's Functionality ({§module-worker-capabilities}),
323
352
  and its operations execute in that Worker's environment — executable families,
324
- runtime schemes, per-Worker tool admission, flag-scoped scheme availability,
325
- and effect policy resolve through the attached Worker — while the operation
353
+ runtime schemes, tools, and capability policy resolve through the attached
354
+ Worker — while the operation
326
355
  journals in the client's own worker ({§connection-lifecycle}) and any entry it
327
356
  writes binds its principal through that client worker. Every dispatch therefore
328
357
  carries two coordinates: `workerId`, the journaling and entry principal, and
@@ -358,7 +387,7 @@ plus a broadcast duplicate. Ordinary project files, private worker entries,
358
387
  and remote resources do not acquire ambient attention merely because they are
359
388
  workspace-addressable.
360
389
 
361
- §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}); stale writes reject at their anchor or compare-and-swap boundary rather than being prevented by a lock ({§line-anchors}, {§membership-edit-write-cas}). 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.
390
+ §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} overlay, a workspace policy, bounds every worker's visible surface uniformly — {§machine-processes}); stale writes reject at their anchor or compare-and-swap boundary rather than being prevented by a lock ({§line-anchors}, {§membership-edit-write-cas}). 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.
362
391
 
363
392
  §actor-boundary-passive-wake **Passive wake follows ownership.** A directed
364
393
  voice wakes an idle worker. A parked continuation resumes when an obligation it
@@ -384,8 +413,8 @@ lineage activity and explicit commons mutations cross the environment door.
384
413
  | Search derivation and catalog render | Kernel. | They are indexes and read-only projections, not entry operations. |
385
414
  | Packet assembly and budget rails | Kernel. | They are the execution substrate on which actor operations depend. |
386
415
 
387
- Git membership includes tracked and untracked-but-not-ignored project files
388
- ({§membership-auto-add}); it does not stage them or run `git add`.
416
+ Git membership is the repository's tracked files and nothing else ({§membership-baseline});
417
+ Plurnk never stages a file or runs `git add`.
389
418
 
390
419
  §turn0-agents-stunt **The project AGENTS.md is a turn-0 stunt.** When
391
420
  `<projectRoot>/AGENTS.md` exists, LoopDocs materializes it as the current worker's private
@@ -404,14 +433,22 @@ neither a hidden database write nor a kernel-owned mirror.
404
433
 
405
434
  §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS`
406
435
  foists turn-0 discovery into the worker's first turn, so a worker opens with a
407
- navigable map instead of blank. An enabled preview executes exactly seven baseline
408
- bodyless FIND surveys in order: enabled Agent Skills (`## FIND0 [+init,+skills]
409
- (worker://~/_plurnk/skills/*.md) <1,-1>`), Plurnk-generated reference families
410
- (`## FIND0 [+init,+skills] (worker://~/_plurnk/skills/plurnk/*.md) <1,-1>`), enabled
411
- tool families (`## FIND0 [+init,+tools] (worker://~/_plurnk/tools/*.md) <1,-1>`),
412
- enabled outbound agents (`## FIND0 [+init,+agents] (worker://~/_plurnk/agents/*.md)
413
- <1,-1>`, {§a2a-agents-catalog}), project files (`## FIND0 [+init] (*)`), workspace commons (`## FIND0 [+init]
414
- (worker:///*)`), and the worker's own space (`## FIND0 [+init] (worker://~/*)`).
436
+ navigable map instead of blank. An enabled preview executes exactly eight baseline
437
+ bodyless FIND surveys in order: Agent Skills (`## FIND0
438
+ [+init,+skills] (worker://~/_plurnk/skills/*.md) <1,-1>`), plurnk references — the
439
+ executors, schemes, and family managers (`## FIND0 [+init,+plurnk]
440
+ (worker://~/_plurnk/plurnk/*.md) <1,-1>`), enabled tools (`## FIND0 [+init,+tools]
441
+ (worker://~/_plurnk/tools/*.md) <1,-1>`), enabled agents (`## FIND0 [+init,+agents]
442
+ (worker://~/_plurnk/agents/*.md) <1,-1>`, {§a2a-agents-catalog}), enabled members
443
+ (`## FIND0 [+init,+members] (worker://~/_plurnk/members/*.md) <1,-1>`,
444
+ {§members-projection}), workspace files (`## FIND0 [+init] (*) <!-- workspace files -->`),
445
+ workspace entries (`## FIND0 [+init] (worker:///*) <!-- workspace entries -->`), and
446
+ private worker entries (`## FIND0 [+init] (worker://~/*) <!-- private worker entries -->`).
447
+ Only those three namespace surveys carry annotations because the bare targets do not
448
+ name their surface; generated paths and classification tags already name every other
449
+ survey. Naming `~` private prevents a worker from offering its own `~` address to
450
+ another worker.
451
+ The word `skills` names Agent Skills and nothing else.
415
452
  The catalogs select every direct document independently of its authored body;
416
453
  ordinary READ supplies its examples and complete instructions on demand. Their
417
454
  log classifications make the opening discovery one `init` set while retaining
@@ -430,7 +467,7 @@ direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
430
467
  unset / `0` disables previews. `log://` is absent because the current worker's
431
468
  log already renders in present mode.
432
469
 
433
- §worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. It preserves one OPEN exact `turnOps` item and dispatches the same source into ordinary PLAN, one archiving COPY, orienting READ/FIND, and terminal `SEND0 [102]` rows (authored in their {§op-mode-phases} execution order). Every orienting row is structurally classified `_plurnk` and `init`; the archiving `COPY (prompt:///<loop>/1)` onto `worker://~/prompts.md <-1>` is classified `_plurnk` and `backup` — the worked COPY specimen, showing the private space as scratch, emitted whenever the loop publishes a prompt ({§prompt-entry}). The PLAN is the canonical {§plan-value} with one `medium`, `in_progress` entry whose content is `Discover the tooling available and survey the workspace file root.`; SEND hands off with `Next: Address the prompt.` The first model request occupies the following turn and therefore begins at database/log turn sequence 2; “turn zero” is the initialization phase's model-facing label, not a zero-based database coordinate. Client and `_plurnk` administrative workers execute operation turns and do not receive model initialization.
470
+ §worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. It preserves one OPEN exact `turnOps` item and dispatches the same source into ordinary PLAN, one archiving COPY, orienting READ/FIND, and terminal `SEND0 [102]` rows (authored in their {§op-mode-phases} execution order). Every orienting row is structurally classified `_plurnk` and `init`; the archiving `COPY (prompt:///<loop>/1)` onto `worker://~/prompts.md <-1>` is classified `_plurnk` and `backup` — the worked COPY specimen, showing the private space as scratch, emitted whenever the loop publishes a prompt ({§prompt-entry}). The PLAN is the canonical {§plan-value} with two entries in order: `Persist Determinations and Decisions` is `memory`, then `Discover the tooling available and survey the workspace file root.` is `in_progress`; SEND hands off with `Next: Address the prompt.` The first model request occupies the following turn and therefore begins at database/log turn sequence 2; “turn zero” is the initialization phase's model-facing label, not a zero-based database coordinate. Client and `_plurnk` administrative workers execute operation turns and do not receive model initialization.
434
471
 
435
472
  ### §machine-processes The machine and its processes: workspace, worker, fork
436
473
 
@@ -466,8 +503,8 @@ terminal history.**
466
503
  | Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
467
504
  | Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
468
505
  | Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
469
- | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, curation effects, tags, folded body intervals, and the matching observation cursor are copied as terminal history. Parent-audience occurrences still pending at the fork boundary belong to the snapshot; later sibling activity does not. |
470
- | §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. |
506
+ | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Durable events, curation effects, tags, current active/folded projection, and the matching observation cursor are copied as terminal history. Parent-audience occurrences still pending at the fork boundary belong to the snapshot; later sibling activity does not. |
507
+ | §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but turn-attached inference calls, their specializations, admission rows, and physical provider requests are not: one issued call or request has one causal branch. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
471
508
  | §machine-processes-entry-inheritance **Worker-owned entries** | Worker | The scheme's mandatory `{§manifest-entry-inheritance}` decides: `snapshot` copies only entries whose channels are all quiescent and remaps ownership; `rederive` copies no bytes and lets the child materializer rebuild them from inherited Functionality; `none` carries nothing. Within a `snapshot` scheme the Worker scheme's generated subtree is always rederived ({§worker-generated-subtree}). Parent and child then diverge. |
472
509
  | Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
473
510
 
@@ -529,7 +566,7 @@ continues to decompose other authorities without treating them as mintable.
529
566
  | Any other spelling | Refused as `name-invalid` before lookup, insertion, or child startup. |
530
567
  | Automatic name | Generated, then admitted through the same predicate. |
531
568
 
532
- §worker-read-scope **Named spaces are ancestry-gated reads**: the reader is the owner or an ANCESTOR (the recursive parent_worker_id walk) — oversight flows down the tree, a parent reads `worker://child/result` across generations, a child cannot snoop upward, and an unknown name or unpermitted reader resolves 404 with no existence leak. Reserved runtime workers obey the same rule; there is no world-readable named space.
569
+ §worker-read-scope **Named spaces are workspace-wide reads**: any worker of the workspace reads `worker://<name>/…` for any other — a parent its child's `result`, a child its parent's, a sibling its sister's. The parent designs the topology by what it names to whom; the engine imposes none (operator ruling 2026-08-26, #394). An unknown name resolves 404. Reserved runtime workers obey the same rule; there is no unnamed world-readable space, and writability is untouched ({§worker-write-scoping}).
533
570
 
534
571
  §worker-write-scoping **Writes are own-space-and-commons only**: a model writes `worker://~/` and `worker:///` — every ancestry-readable named authority is read-only to it (403), while an unreadable name remains 404 under {§worker-read-scope}. `owner_id` is engine-stamped from the dispatch context, never model-set. Nothing worker-authored can land under another principal. The entry-copy seam (COPY/MOVE) is pathname-keyed and addresses the commons; a space's content moves via READ + EDIT. The one exception inside a writable space is the generated subtree below.
535
572
 
@@ -579,7 +616,7 @@ literal `workers.name` value.
579
616
  remapped (source → branch) — so the branch opens with the parent's notes and
580
617
  diverges on its own edits: *fork = everything-in-common-but-name*.
581
618
  - **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.
582
- - §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.
619
+ - §worker-delegation-inherits-policy **Delegation cannot widen authority.** WORK and FORK copy the delegating actor's complete effective capability policy into the child's immutable `capability_bound`; later widening of any parent layer cannot enlarge that child. Every fresh delegated loop carries that complete effective attenuation and the delegating loop's proposal disposition, including a loop created by SEND to an idle Worker. SEND into an active or parked loop leaves that loop's immutable policy untouched. The bound is delegation authority captured by value, not a client binding or a live parent-policy link.
583
620
  - §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.
584
621
 
585
622
  Untagged worker control rides the daemon's inject seam (active→fold, idle→enqueue+drain), so the handler creates/branches the worker and hands off; the daemon owns provider + system prompt. Tagged WORK/FORK instead enqueue a fresh loop without starting its drain; {§worker-branch-batch} becomes its sole starter. FORK/WORK carry the seed task in the body and are their own ops, dispatched to worker control — never the entry-copy path.
@@ -589,6 +626,15 @@ Untagged worker control rides the daemon's inject seam (active→fold, idle→en
589
626
  Branch-tagged WORK/FORK serializes ordinary Git branches over the one project
590
627
  checkout. It creates no worktrees, alternate roots, hidden merges, or stashes.
591
628
 
629
+ §branch-delegation-disabled **Off the surface until specified (#396).** The form is
630
+ not offered to the model: the teaching carries no `[branch]` slot, and unless the
631
+ operator sets `PLURNK_SERVICE_BRANCH_DELEGATION=1` a WORK/FORK signal is refused up
632
+ front as `501 branch-delegation-disabled`, naming the signal-less form. Twelve
633
+ branch delegations across the benchmarks produced no organic success; the
634
+ preconditions below are invisible to the model until the refusal, and any label on
635
+ WORK/FORK reads as a branch order. The batches below remain the implementation behind
636
+ that knob and keep their witnesses.
637
+
592
638
  §worker-branch-batch-exclusive **Stop the workspace; serialize
593
639
  ordinary branches.** A branch signal on WORK/FORK creates a durable batch keyed
594
640
  to the parent turn. The batch queues one exclusive workspace gate before that
@@ -647,8 +693,9 @@ The remaining worker surfaces are:
647
693
  **2xx deliverable is born OPEN** (its body
648
694
  materialized into the parent's packet, not hidden behind a fold): a child's
649
695
  success must reach the parent open and awakening, never a bodyless row. An
650
- non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly,
651
- so no child termination is silent to its owner; collection is lineage
696
+ non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly —
697
+ including a spawn that dies before its first turn, such as a branch batch refused at
698
+ git-preflight — so no child termination is silent to its owner; collection is lineage
652
699
  supervision, never a
653
700
  verb. The **pull** side mirrors the push: a path-absent
654
701
  `## READ0 (worker://<name>)` collects that same result on demand for a
@@ -816,7 +863,7 @@ boundary.
816
863
  - §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.
817
864
  - §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.
818
865
  - §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.
819
- - §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}). A pending client interaction also lost its exact awaiting operation, so boot removes the orphan instead of replaying work or inventing a response ({§client-interactions}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation 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.
866
+ - §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every pending physical provider request first settles as an error with absent usage and explicitly unknown cost; then its logical generation or embedding call closes, including a workspace-only embedding with no turn to invent. Recovery never fabricates zero evidence. Every durable proposed operation likewise lost its process-local resolution waiter and settles as a visible `500 owner_vanished` occurrence rather than an unresolvable interrupt ({§proposal-list}). A pending client interaction also lost its exact awaiting operation, so boot removes the orphan instead of replaying work or inventing a response ({§client-interactions}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation 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.
820
867
 
821
868
  ---
822
869
 
@@ -834,6 +881,24 @@ Three current entry points:
834
881
 
835
882
  §provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow`, `maxInputTokens`, and `maxOutputTokens` carry known model limits; `outputBudget` is the total generation envelope, optional `reasoningBudget` is its strict subset, and `inputCapacity` is the stable intersection of known input constraints ({§tokenomics}). Unknown facts remain `null`. `model` identifies persisted turn/provider evidence. Local GBNF admission also consumes `constrainsOutput` ({§grammar-configuration-admission}).
836
883
 
884
+ §inference-ledger **Logical inference is provider-neutral and physical requests
885
+ have one ledger.** Every inference opens one `inference_calls` identity with a
886
+ mandatory workspace, optional real causal turn, ordered kind, request model,
887
+ and forward-only lifecycle. Its specialization owns only domain evidence:
888
+
889
+ | Kind | Specialization | Causal scope |
890
+ |---|---|---|
891
+ | `emission`, `bare` | `model_calls`: normalized response/failure and capacity | A model/inference turn is required; only emission has `turn_attempts` admission evidence. |
892
+ | `embedding_query`, `embedding_documents` | `embedding_calls`: input/output cardinality, artifact metadata, or failure | Workspace is required; a turn is attached only when the operation has one. |
893
+
894
+ Every physical request is an ordered `provider_requests` child opened before
895
+ I/O and settled once. Hosted generation and embeddings use that same observer;
896
+ local embeddings retain their logical call and create no fictitious physical
897
+ request. Turn-attached embeddings contribute to turn, loop, worker, and
898
+ workspace accounting; workspace-only embeddings contribute only to workspace
899
+ accounting. Neither is packet occupancy, so only an emission may supply the
900
+ latest context gauge.
901
+
837
902
  §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}).
838
903
 
839
904
  ### §provider-guarantees Engine → provider guarantees
@@ -848,22 +913,29 @@ Three current entry points:
848
913
 
849
914
  ### §emission-admission Provider emission admission
850
915
 
851
- 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}).
916
+ 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 requires at least one parsed source operation, no `unparsedTail`, and a trustworthy effective envelope. Canonical source begins with PLAN and ends with a terminal SEND. If no valid leading PLAN or terminal SEND was parsed, the parser supplies an empty PLAN or bodyless `SEND [102]`, records its exact hard diagnostic, and Core admits the useful operations instead of resampling. Both diagnostics participate in one ordinary struck turn, never one strike apiece. An authored PLAN or terminal SEND remains a real boundary, so an error outside either authored edge, post-terminal content, a boundary-destroying tail, or no source operation 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}). The accepted packet retains the provider's source bytes exactly in response evidence and `turnOps`; synthetic envelope statements exist only in the normalized operation program and its durable rows.
852
917
 
853
- §safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ, FOLD, or OPEN only when splitting its raw target at top-level comma or whitespace separators produces at least two members and every member independently parses as an explicit `scheme://` URI. Request-metadata blocks are opaque to this split. Each member becomes one ordinary statement with an independent dispatch outcome and log row, in authored member order; scheduling may still move the complete operation class under {§op-mode-phases}. Otherwise the target remains exactly singular, including local filenames containing spaces or commas. The stored `turnOps` and authored command count remain unexpanded, and no other operation admits target groups.
918
+ §safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ, FOLD, OPEN, or KILL only when splitting its raw target at top-level comma or whitespace separators produces at least two members and every member independently parses as an explicit `scheme://` URI. Request-metadata blocks are opaque to this split. Each member becomes one ordinary statement with an independent dispatch outcome and log row, in authored member order; scheduling may still move the complete operation class under {§op-mode-phases}. Otherwise the target remains exactly singular, including local filenames containing spaces or commas. The stored `turnOps` and authored command count remain unexpanded, and no other operation admits target groups.
854
919
 
855
- 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. A call that ends without response evidence leaves that admission row unclassified (`accepted IS NULL`) and does not consume the emission-attempt ceiling. 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 extends `turns.packet` with response evidence; 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.
920
+ 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 `inference_calls` row with its `model_calls` specialization and emission-specific `turn_attempts` admission row. A call that ends without response evidence leaves that admission row unclassified (`accepted IS NULL`) and does not consume the emission-attempt ceiling. Beneath the logical 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 extends `turns.packet` with response evidence; 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.
856
921
 
857
- 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 emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice: `Your previous response contained an unrecoverable syntax error. No operations were performed. Try again.` followed by `Parser: <the latest attempt's first diagnostic>` with its `content-offset` position — the model sees why, at which line, against its own projected text. Attempt count and rail state never become model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
922
+ 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 emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice: `Response rejected before dispatch; no operations were performed.` followed by `Parser: <the latest attempt's first diagnostic>` with its `content-offset` position — the model sees why, at which line, against its own projected text. The Notice states only observed admission facts; it does not classify the response as unrecoverable, infer why generation ended, or prescribe intent beyond the parser-owned diagnostic. Attempt count and rail state never become model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
858
923
 
859
- 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.
860
- The Problem recovery states that only the failed operation needs correction
861
- because its parsed siblings were retained; the parser-owned detail states the
862
- specific syntax rule.
924
+ An admitted program may contain bounded malformed statements or recovered
925
+ envelope defaults. Parsed operations still dispatch; each hard parser diagnostic
926
+ becomes one durable model-origin `error` row with the parser's exact detail under
927
+ {§parse-diagnostics} and status 400. These failures are committed before the
928
+ terminal disposition, participate in the ordinary strike rail, and prevent SEND
929
+ signal `200` or an already-drained signal `202` from concluding before the model
930
+ sees them in the next packet. This is operation recovery, not provider
931
+ resampling. A malformed statement's Problem records the factual
932
+ `siblingsRetained: true` extension; an envelope-default Problem states only the
933
+ observed boundary failure and exact default applied.
863
934
 
864
935
  §invalid-emission-attempts Exhausting the emission-attempt budget opens the
865
936
  single informed recovery turn above. Consecutive exhaustion of that turn
866
- terminates the loop at 500 without spending an engine strike.
937
+ terminates the loop at 500 without spending an engine strike, with detail `No
938
+ Plurnk turn was admitted after <N> emission attempts.`
867
939
 
868
940
  §turn-never-blank An admitted turn whose operation fails — during parsing or
869
941
  dispatch — is categorically different: its failed operation row enters
@@ -889,7 +961,7 @@ shared contract {§plugin-attribution}:
889
961
  | 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. |
890
962
  | Composition | Core flattens, deduplicates, and sorts the tags. The resulting non-empty array rides `generate({ attributions })`; an empty set omits that provider field. |
891
963
  | 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}). |
892
- | 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. |
964
+ | Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Every generation-kind `inference_calls` row carries that call's exact set, including response-less failures. |
893
965
  | 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. |
894
966
 
895
967
  Runtime hooks are synchronous and receive only the attempt coordinates. A hook
@@ -998,7 +1070,7 @@ meaning of an authored URI authority before any entry capability is exposed:
998
1070
  host, non-default port, path, and serialized query are identity; query order,
999
1071
  duplicates, and an explicit empty `?` survive. A fragment is a Plurnk channel
1000
1072
  selector, not network identity or transport. URL userinfo is rejected and
1001
- request metadata never enters identity. Plain `http` routes through `https`,
1073
+ scheme metadata never enters identity. Plain `http` routes through `https`,
1002
1074
  just as `ws` routes through `wss`; those implementation aliases never alias
1003
1075
  resources, and the secure face is the one taught — `http` stays supported
1004
1076
  for the endpoint that requires it, never advertised as a peer. `SchemeCtx.entries` binds every cap to the addressed protocol.
@@ -1045,43 +1117,43 @@ render-time filtering.
1045
1117
 
1046
1118
  §fs-canonical-name **One canonical name, storage ≡ wire: the git pathspec.** Member keys follow gitformat-index(5) verbatim (reference edition: git 2.47.3): relative to the workspace `project_root`, without leading slash, `/`-separated, no trailing slash or NUL. Directories are never entries and the root needs no name. When `project_root` is below the containing repository's top level, Git members above it naturally use the same `../`-prefixed CWD-relative names that `git ls-files` emits without `--full-name`; these are not outside-repository mounts. The database stores that root-relative key directly because workspace identity is rooted at the access point. Every model spelling canonicalizes before storage or comparison.
1047
1119
 
1048
- §fs-visibility-grantors **File visibility has two represented grantors; Plurnk never invents a private third one.** A file member is admitted by the active Git substrate or by an ordinary `pick` constraint. A `pick` is either explicit client policy or the exact, inspectable record of an accepted creation ({§fs-create-generated-pick}); both resolve to `constraint` membership. AGENTS.md remains auto-pulled as POLICY ({§policy-sections}), deliberately not a file member. A physically existing path that neither Git nor `pick` admits does not exist for the model and cannot be overwritten.
1120
+ §fs-visibility-grantors **File visibility has two represented grantors; Plurnk never invents a private third one.** A file member is admitted by the active Git substrate or by an ordinary `include` row of the overlay. An `include` is either a projected `members` definition ({§members-projection}) or the exact, inspectable record of an accepted creation ({§fs-create-record}); both resolve to `constraint` membership. AGENTS.md remains auto-pulled as POLICY ({§policy-sections}), deliberately not a file member. A physically existing path that neither Git nor an `include` admits does not exist for the model and cannot be overwritten.
1049
1121
 
1050
- §fs-write-surface **The write surface — one admission and incorporation path.** Existing writes remain membership-gated. An absent path additionally crosses the effective creation scope and the complete constraint/Git policy before a proposal is issued. EDIT, COPY destinations, and MOVE destinations use this same path regardless of whether the producer is a model, client, plugin, or `_plurnk`. A COPY or MOVE destination region on an absent entry is admitted only as the append form `<-1>`, which creates the entry with the source content — appending to nothing is creation; any other region on an absent entry is `destination-region-not-found`.
1122
+ §fs-write-surface **The write surface — one admission and incorporation path.** Existing writes remain membership-gated. An absent path additionally crosses the effective creation scope and the complete constraint/Git policy before a proposal is issued. EDIT, COPY destinations, and MOVE destinations use this same path regardless of whether the producer is a model, client, plugin, or `_plurnk`. A COPY or MOVE destination region on an absent entry creates the entry when it is `<-1>`, the whole-source form `<1,-1>`, or a whole-line range from line 1 whose final line exactly equals the selected source's resulting line count. These scopes all describe the complete new value; any other region on an absent entry is `destination-region-not-found`.
1051
1123
 
1052
1124
  | Case | Required admission | Accepted result |
1053
1125
  |------|--------------------|-----------------|
1054
1126
  | §fs-create-disabled Absent path, effective scope `none` | None | Refuse without touching disk. |
1055
- | §fs-create-root Absent path inside `project_root` | Effective scope `root` or `namespace`; no matching `hide` or `view` | Exclusive CREATE (`open(O_CREAT\|O_EXCL)` semantics), then incorporation below. |
1056
- | §fs-create-namespace Absent canonical `../` path | Effective scope `namespace`; no matching `hide` or `view` | Exclusive CREATE, then an exact `pick` so the outside member is read-write. |
1057
- | §fs-create-ignored Absent path ignored by active Git | Matching **explicit** `pick` | Exclusive CREATE through that pick; an automatic/generated pick never overrides Git ignore. |
1058
- | §fs-create-git Absent in-root path admitted by active Git | Not ignored | Exclusive CREATE followed by successful `git add -- <path>`; a staging failure falls back to an exact generated pick. |
1059
- | §fs-create-pick Absent admitted path without Git incorporation | Existing explicit pick or automatic incorporation permitted | Exclusive CREATE followed by an exact generated pick when no explicit pick already covers it. |
1060
- | §fs-write-member Existing in-root member | Git or pick membership; no matching `view` | Proposal-gated EDIT. |
1061
- | §fs-write-outside Existing canonical `../` member | Pick membership; no matching `view` | Proposal-gated EDIT. Git-only outside members are read-only. |
1127
+ | §fs-create-root Absent path inside `project_root` | Effective scope `root` or `namespace`; no matching exclusion | Exclusive CREATE (`open(O_CREAT\|O_EXCL)` semantics), then incorporation below. |
1128
+ | §fs-create-namespace Absent canonical `../` path | Effective scope `namespace`; no matching exclusion | Exclusive CREATE, then an exact creation record so the outside member is read-write. |
1129
+ | §fs-create-ignored Absent path ignored by active Git | Matching `members` definition | Exclusive CREATE through that definition; a creation record or model definition never overrides Git ignore. |
1130
+ | §fs-create-git Absent in-root path admitted by active Git | Not ignored | Exclusive CREATE followed by an exact creation record (`source: "create"`); never `git add` ({§membership-baseline}). |
1131
+ | §fs-create-definition Absent admitted path without Git incorporation | A projected `members` definition or automatic incorporation permitted | Exclusive CREATE followed by an exact creation record when no `members` definition already covers it. |
1132
+ | §fs-write-member Existing in-root member | Git or include membership | Proposal-gated EDIT. |
1133
+ | §fs-write-outside Existing canonical `../` member | Include membership | Proposal-gated EDIT. Git-only outside members are read-only. |
1062
1134
  | §fs-write-nonmember Existing non-member | None | Refuse; reveal occupancy only, never content. |
1063
1135
 
1064
- §fs-create-incorporation **Creation incorporation is durable workspace state, not a transient entry exception.** `workspace_constraints.source` distinguishes an operator/client-authored `explicit` constraint from a runtime-authored `create` constraint. An explicit row interprets `glob` as a pattern; a generated row interprets the same field as one literal canonical path, so legal filename metacharacters never become wildcard syntax. Generated constraints appear through the ordinary `workspace.constraints` client surface. An explicit pick covering the same path always wins and is never demoted.
1136
+ §fs-create-incorporation **Creation incorporation is durable workspace state, not a transient entry exception.** `workspace_constraints.source` distinguishes the engine's `create` record of a file Plurnk wrote from the `members` family's projected rows (`members`: human-authored, `model`: model-proposed — {§members-projection}). A projected row interprets `glob` as a pattern; a creation record is one exact canonical path, never reinterpreted as a pattern, and the family's projection never overwrites or retires it.
1065
1137
 
1066
- | Event | Generated-pick lifecycle |
1138
+ | Event | Creation-record lifecycle |
1067
1139
  |-------|--------------------------|
1068
- | §fs-create-generated-pick Successful creation not incorporated by Git or an existing explicit pick | Insert exact `{ effect: "pick", glob: canonicalPath, source: "create" }`. |
1140
+ | §fs-create-record Successful creation not covered by a projected `members` definition | Insert exact `{ effect: "include", glob: canonicalPath, source: "create" }`. |
1069
1141
  | §fs-create-copy COPY to a new path | Incorporate the destination independently; the source is unchanged. |
1070
- | §fs-create-move MOVE to a new path | Incorporate the destination, then remove the source's generated exact pick after deleting the source. |
1071
- | §fs-create-kill KILL or accepted whole-resource deletion | Remove the deleted path's generated exact pick. |
1072
- | §fs-create-explicit-promotion Explicit `pick` added at the same exact path | Promote/retain the row as `source: "explicit"`; later automatic cleanup cannot remove it. |
1073
- | §fs-create-masked A later `hide` or active Git-ignore rule excludes a generated-pick member | Preserve the generated pick as dormant policy; removing the exclusion restores membership when the file still exists. A later `view` leaves it visible but read-only. |
1074
- | §fs-create-ambient-delete Reconciliation confirms a generated-pick path disappeared outside Plurnk | Remove the generated exact pick; explicit picks remain operator policy. |
1142
+ | §fs-create-move MOVE to a new path | Incorporate the destination, then remove the source's creation record after deleting the source. |
1143
+ | §fs-create-kill KILL or accepted whole-resource deletion | Remove the deleted path's creation record. |
1144
+ | §fs-create-definition-overlap A `members` definition projected at the same exact path | The creation record stays as it is; the definition keeps admitting the path after the record is retired. |
1145
+ | §fs-create-masked A later exclusion or active Git-ignore rule excludes a created member | Preserve the creation record as dormant provenance; removing the exclusion restores membership when the file still exists. |
1146
+ | §fs-create-ambient-delete Reconciliation confirms a created path disappeared outside Plurnk | Remove the creation record; projected definitions are untouched. |
1075
1147
 
1076
1148
  The file-creation invariants are deliberately redundant with the matrices only
1077
1149
  where the invariant closes an architectural failure mode:
1078
1150
 
1079
- - §file-create-no-orphans A successful create always ends in Git membership or a real pick; no accepted file is orphaned from the workspace that created it.
1151
+ - §file-create-no-orphans A successful create always ends in a projected definition or a creation record; no accepted file is orphaned from the workspace that created it.
1080
1152
  - §file-create-no-clobber Creation is exclusive and an existing non-member remains unreadable and non-overwritable.
1081
- - §file-create-exclusions-win `hide` and `view` outrank all automatic creation; active Git ignore is overridden only by an explicit pick.
1153
+ - §file-create-exclusions-win An exclusion outranks all automatic creation; active Git ignore is overridden only by a `members` definition.
1082
1154
  - §file-create-scope The effective creation scope is the minimum of the service ceiling and workspace setting; no call site or producer may widen it.
1083
1155
  - §file-create-producer-neutral The file contract depends on the operation and target, never the producer identity.
1084
- - §file-create-single-owner File membership owns prospective admission, incorporation choice, and generated-pick lifecycle; file operations consume that decision rather than re-deriving Git and constraint policy.
1156
+ - §file-create-single-owner File membership owns prospective admission, incorporation choice, and creation-record lifecycle; file operations consume that decision rather than re-deriving Git and constraint policy.
1085
1157
  - §file-create-transaction Success requires both exclusive disk creation and durable incorporation. Approval re-resolves physical containment and policy, so a proposal-time parent cannot be swapped for an outside-pointing symlink. Incorporation failure removes the created entry and file; incomplete rollback is an explicit partial-failure Problem.
1086
1158
 
1087
1159
  Refusing an occupied non-member follows the POSIX exclusive-create precedent:
@@ -1139,7 +1211,9 @@ Registration precedes loop affinity:
1139
1211
 
1140
1212
  - §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.
1141
1213
 
1142
- - §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.
1214
+ - §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. When validation identifies one malformed statement, that row receives its exact 4xx Problem while every otherwise-valid sibling receives 424 Failed Dependency without borrowing the malformed statement's coordinates. 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.
1215
+ - §edit-batch-receipt **A refused batch names everything wrong with it.** Validation of a resource batch resolves every line anchor and checks every region pair before any verdict, so one receipt carries the complete correction. A `line-anchor-collision` lists every anchor that no longer resolves in `staleAnchors` (anchor, kind, and the matching lines when ambiguous). An `overlapping-edits` refusal lists every conflicting pair with its relation (same insertion point, duplicate, one contains the other, overlap) in `conflicts`, the regions that conflict with nothing in `cleanRegions`, and keeps the first pair in `conflictingRegions`. Both carry `editCount` and `applied: 0`, and their recovery prose states those counts, so the model never learns a batch's defects one resubmission at a time and never has to guess whether anything was written. Every row of the refused batch carries the same receipt.
1216
+ - §edit-batch-merges **Four resolutions are certain enough to apply; everything else stays a refusal, and every resolution is reported on its row.** Before the conflict check, core and the Slicer resolve exactly these shapes: (1) an identical twin (same region, same body up to trailing whitespace and trailing newlines — `whitespaceOnly: true` when they differed that way) is applied once and the twin's row carries `merged: {rule: "duplicate-of", of}` with no effect of its own; (2) two insertions at one point land in authored order (`same-insertion-point`); (3) two whole-line regions meeting on exactly one shared line, where that line's text appears verbatim in exactly one of the two bodies, give the line to that body and shrink the other by one (`shared-endpoint`, with the line, its text, the authored and applied coordinates, and `claimedBy`) — the inclusive `<SL,EL>` read as half-open, the commonest overlap on the 2026-08-29 runs; (4) a body whose every non-empty line carries this resource's own rendered `@xxxxx L:` prefix, hash-verified at its ordinal against the current anchors, is the READ rendering pasted back: the prefixes are stripped (`rendered-prefix-stripped`), and a look-alike that does not verify is written as authored with `rendered-prefix-unverified` reported — the hash is the proof, so intentional text of that shape is never altered. (5) one region inside another resolves when the inner region's original lines occur exactly once in the outer body: the inner change is relocated there (`contained-relocated`, with the outer index, the line within the outer body, and the authored coordinates); (6) an outer body that already carries the inner body makes the inner redundant (`contained-already-applied`). A shared endpoint that no body reproduces, and a containment whose inner lines occur zero or several times in the outer body, remain 409 with the line (and its text) or the containing region named. Each applied resolution is also a notice. Receipts are built from the edits as applied; a dropped twin's row carries its merge fact instead of an effect.
1143
1217
 
1144
1218
  ### §orchestration Cross-scheme orchestration
1145
1219
 
@@ -1174,7 +1248,7 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
1174
1248
  - `## SEND0 [200] (path)` — write body into resource (WS message, exec stdin).
1175
1249
  - `## SEND0 [499] (path)` — cancel active subscription ({§stream}).
1176
1250
 
1177
- - §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.
1251
+ - §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.
1178
1252
  - §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.
1179
1253
  - §channel-selection-visibility **Channel selection is decision-time information, not a guess** — every multi-channel resource presents its channels with extents wherever FIND presents the resource: broad results list each channel's path, mimetype, tokens, and lines (default channel first), and matcher locations name the channel their line coordinates address. The packet never presents channels as equal and indistinguishable; extents derive from the stored channels by construction. Budget enforcement stays with {§overflow-turn} — this is information, not a second guard.
1180
1254
 
@@ -1217,7 +1291,7 @@ Engine → scheme guarantees:
1217
1291
  - `ctx` is fresh per call. No mutation across calls.
1218
1292
  - §universal-read-composition **Exact READ has one composition.** Core resolves
1219
1293
  canonical identity and owner once, gives a data scheme its optional
1220
- `prepareRepresentation({ target, authority, pathname })` opportunity, reads the complete
1294
+ `prepareRepresentation({ target, metadata, authority, pathname })` opportunity, reads the complete
1221
1295
  canonical channels, selects the authored channel, applies binary and
1222
1296
  text-coordinate rules, and finally composes that channel's durable producer
1223
1297
  result. Preparation receives neither fragment nor `lineMarker`; finite work
@@ -1272,7 +1346,7 @@ consume these public methods:
1272
1346
  | `detect`, `process` | Resolve mimetypes, extents, readable content, symbols, and references. |
1273
1347
  | `projectionIdentity` | Identify installed reader behavior for derived entries and search artifacts that consume symbols and references. |
1274
1348
  | `query` | Execute glob/regex/JSONPath/XPath through `@plurnk/plurnk-schemes/Matcher`, which maps typed outcomes to operation results. |
1275
- | `embedderInfo`, `embedBatch`, `tokenizer` | Plan and derive semantic-search chunks without reaching into artifact packages. |
1349
+ | `embedderInfo`, `embedDocuments`, `tokenizer` | Plan and derive semantic-search chunks without reaching into artifact packages. |
1276
1350
 
1277
1351
  `@plurnk/plurnk-contracts` owns model-facing matcher syntax; parsed content
1278
1352
  dialects pass to `Mimetypes.query` without reclassification. Mimetype handlers
@@ -1323,12 +1397,11 @@ internal contract failure, never a reason to substitute the pure heuristic.
1323
1397
  | READ/EDIT and COPY/MOVE scope | Admit text regions or return 415. |
1324
1398
  | Search derivation | Build graph/FTS/vector artifacts or mark nonsemantic. |
1325
1399
 
1326
- The default service installation includes its structured, document, embedding,
1327
- and tokenizer leaves through the service manifest. The lean framework also
1328
- supports direct consumers that assemble a different set. Tree-sitter grammar
1329
- WASM leaves and third-party handlers remain independently installable and
1330
- resolve from the same consumer-visible package graph under trust-gated
1331
- discovery ({§mimetype-discovery}).
1400
+ The default service installation includes its structured, document, and
1401
+ embedding leaves through the service manifest. Exact tokenizer vocabularies,
1402
+ tree-sitter grammar WASM leaves, and third-party handlers remain independently
1403
+ installable and resolve from the same consumer-visible package graph under
1404
+ trust-gated discovery ({§mimetype-discovery}).
1332
1405
 
1333
1406
  **Token accounting.** The daemon injects no tokenizer into `Mimetypes`; content
1334
1407
  projection is independent of packet budgeting. Core uses the stable
@@ -1374,10 +1447,10 @@ flowchart LR
1374
1447
 
1375
1448
  §derivation-exhaustive Identical projections attach the same immutable artifact regardless of their source table. Search primitives therefore consume only `{key, deepHash}` candidates and cannot depend on entry or log storage. Semantic and graph FIND require every selected channel candidate—and every channel in graph's relationship universe—to be attached. An incomplete set returns 503 with `problem.search = {state:"incomplete", indexed, total}`; it never silently searches a partial corpus. Explicit membership changes may warm eagerly; every model turn joins exhaustive derivation before dispatch. Passive workspace creation and attachment do not launch it. The incomplete response is therefore an interface invariant and diagnostic, not a lazy-search mode.
1376
1449
 
1377
- The graph projection stores only addressable symbol names. A structured-data handler may legitimately emit an empty key into its symbols channel, but the `@graph` matcher cannot name an empty symbol; that one definition is omitted from graph storage without suppressing FTS, vectors, or the remaining definitions. Invalid references and other persistence violations still fail the resource derivation explicitly.
1450
+ The graph projection stores only addressable symbol names. A structured-data handler may legitimately emit an empty key into its symbols channel, but the `&graph` matcher cannot name an empty symbol; that one definition is omitted from graph storage without suppressing FTS, vectors, or the remaining definitions. Invalid references and other persistence violations still fail the resource derivation explicitly.
1378
1451
 
1379
1452
  The pass tiles the exact readable text into token-budgeted fragment strings and
1380
- sends every tile for one resource through one ordered `mimetypes.embedBatch`
1453
+ sends every tile for one resource through one ordered `mimetypes.embedDocuments`
1381
1454
  call; it never re-runs a format handler against partial fragments. Workspace
1382
1455
  warms coalesce; a request arriving during a pass forces one final rescan.
1383
1456
  Progress exposes `preparing`, `indexing`, `complete`, or `failed`. Producer
@@ -1466,12 +1539,17 @@ Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkState
1466
1539
  A scheme declaring `lineAnchors: true`, or `textEditScopes: true` with model
1467
1540
  write authority, publishes the contracts-owned {§text-line-anchor-syntax}.
1468
1541
  Model-writable `textEditScopes` implies anchors; `lineAnchors` alone makes no EDIT claim. For canonical model-facing
1469
- resource identity `R`, one-based line ordinal `L`, configured non-negative
1470
- neighbor count `C`, and ordered content array `W` containing that line and up to
1471
- `C` complete lines on either side (all excluding separators), core hashes the
1472
- JSON tuple `["plurnk-line-anchor-v1",R,L,C,W]` with SHA-256, interprets the
1473
- digest as a big-endian integer modulo `62^5`, and encodes five fixed-width
1474
- characters with alphabet `0-9A-Za-z`. The universal READ projector derives
1542
+ resource identity `R`, configured non-negative neighbor count `C`, ordered
1543
+ content array `W` containing that line and up to `C` complete lines on either
1544
+ side (all excluding separators), and the line's offset `O` within `W`
1545
+ (`min(L-1, C)` for one-based ordinal `L`), core hashes the JSON tuple
1546
+ `["plurnk-line-anchor-v2",R,C,O,W]` with SHA-256, interprets the digest as a
1547
+ big-endian integer modulo `62^5`, and encodes five fixed-width characters with
1548
+ alphabet `0-9A-Za-z`. The ordinal itself is not hashed (#428): a line keeps its
1549
+ anchor wherever it moves while its content and neighborhood are unchanged, so
1550
+ edits above a line — the model's own earlier edits included — never stale the
1551
+ anchors below them; identical neighborhoods share one anchor and resolve as
1552
+ ambiguous with the matching lines, never as a silent landing on a twin. The universal READ projector derives
1475
1553
  anchors from the complete canonical selected channel before applying the
1476
1554
  authored text slice; its durable result retains the canonical derivation
1477
1555
  identity and anchors aligned with returned lines. Packet rendering right-aligns
@@ -1486,7 +1564,11 @@ For READ/LOOK and COPY/MOVE source or destination selection, core resolves every
1486
1564
  anchor against the addressed current complete content before applying the
1487
1565
  ordinary numeric text-coordinate contract. Exactly one current match lowers to
1488
1566
  its numeric line; zero or multiple matches return 409 `line-anchor-collision`,
1489
- and an anchor in a column position returns 400. COPY/MOVE mutation owners retain
1567
+ with `retryable: false` because resolving the collision requires a new READ and
1568
+ different coordinates rather than automatic replay. An anchor in a column
1569
+ position returns 400 stating that four-coordinate
1570
+ column slots are numeric and that `<@start,@end>` is the whole-line anchor
1571
+ range. COPY/MOVE mutation owners retain
1490
1572
  the resolved endpoint neighborhoods as compare-and-swap preconditions. There is
1491
1573
  no revision sidecar or fuzzy relocation. A range authenticates both endpoint
1492
1574
  neighborhoods, so every line of a range up to `2C + 2` lines is covered; a
@@ -1501,7 +1583,7 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
1501
1583
  - §edit-null-clears Writes the body; `body: null` clears it.
1502
1584
  - §edit-status-201-200 Returns `{ status: 201, entryId }` for a new entry and
1503
1585
  `{ status: 200, entryId }` for a content update.
1504
- - §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}).
1586
+ - §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's idempotence ({§open-fold}). Its terse detail states the observed equality and the valid empty-body deletion shape; it never presumes that repetition or retrieval is the intended recovery. The operation's log classification remains independent ({§log-item-tags}).
1505
1587
  - §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.
1506
1588
  - §edit-line-anchors An anchored EDIT resolves under {§line-anchors} and carries
1507
1589
  its endpoint checks as a core-private mutation precondition. Otherwise-valid
@@ -1518,9 +1600,11 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
1518
1600
  that changes before mutation, or a representation that changes in the final
1519
1601
  check/write gap returns the same neutral **409 `edit-collision`** and preserves
1520
1602
  the winner's content. Its public detail says only that EDIT collided with
1521
- another change and directs the model to READ and retry; it does not assign
1522
- fault or reveal which detection layer won. Concurrent correct workers are an
1523
- ordinary cause. Core resolves anchors, scheme handlers receive only numeric
1603
+ another change and directs the model to READ before selecting current
1604
+ coordinates; `retryable: false` forbids automatic replay of the identical
1605
+ stale request. It does not assign fault or reveal which detection layer won.
1606
+ Concurrent correct workers are an ordinary cause. Core resolves anchors,
1607
+ scheme handlers receive only numeric
1524
1608
  coordinates, the shared entry mutation owner rechecks selected endpoint
1525
1609
  neighborhoods against its exact snapshot, and atomic identity/channel claims
1526
1610
  and storage predicates close the remaining races.
@@ -1557,18 +1641,30 @@ operation requires a target, matcher, or unsigned tag. Add and remove terms for
1557
1641
  the same tag conflict. Successful visibility and classification changes land as
1558
1642
  one curation event whose exact per-row deltas are durable. Engine policy may
1559
1643
  apply its separately specified diagnostic classifications, such as `overflow`.
1560
- Every classification lives once in `log_tags`, is erased with its row, and is
1561
- copied with log history on fork.
1644
+ Every classification lives once in `log_tags`, remains forensic evidence when
1645
+ KILL retires its row's projection, and is copied with log history on fork.
1646
+
1647
+ ### §log-history-projection Durable history and active projection
1648
+
1649
+ | Layer | Owner | Curation contract |
1650
+ |---|---|---|
1651
+ | Durable event | `log_entries` | One chronological execution fact. Ordinary Plurnk operations never erase it; its original body and initial folded state remain available to the client journal, digest, and fork forensics. Containing turn, worker, or workspace teardown may cascade the history. |
1652
+ | Active projection | `log_entry_projections` | One current worker-facing state per event. OPEN/FOLD change folded body intervals while active. Log-KILL atomically changes active to inactive and cannot be reversed; inactive rows are absent from packet rendering, log READ/FIND, failure pointers, semantic discovery, token accounting, and later curation. |
1653
+
1654
+ The successful curation operation and every exact target transition are durable
1655
+ in the same commit. KILL against another scheme retains that scheme's ordinary
1656
+ resource or process semantics; this projection contract is specific to
1657
+ `log:///`.
1562
1658
 
1563
1659
  ### §open-fold OPEN / FOLD
1564
1660
 
1565
1661
  AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: TextLineMarker | null }`.
1566
1662
 
1567
- OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). Without a scope, FOLD hides and OPEN reveals the whole canonical log body. With a one-line or inclusive two-line scope, each operation changes only that body's intersecting body-relative physical lines. An anchor may be one already published on that immutable body or one returned by READing its `log:///` identity; numeric lines outside a selected body and absent or ambiguous anchors are successful per-body no-ops. Both select rows by target, matcher, and the symmetric ALL-tags filter before independently applying the scope and tag changes to each selected row. Folded intervals are durable, sorted, disjoint, and compositional; `[]` is wholly open and `[[1,-1]]` wholly folded. The canonical body remains complete through log READ/FIND regardless of visibility. Rows and bodies persist, and classification changes still land when visibility is a no-op. Malformed targets, unsupported coordinate arity, and nonexistent exact coordinates fail at their owning boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1663
+ OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). Without a scope, FOLD hides and OPEN reveals the whole canonical log body. With a one-line or inclusive two-line scope, each operation changes only that body's intersecting body-relative physical lines. An anchor may be one already published on that immutable body or one returned by READing its `log:///` identity; numeric lines outside a selected body and absent or ambiguous anchors are successful per-body no-ops. Both select rows by target, matcher, and the symmetric ALL-tags filter before independently applying the scope and tag changes to each selected row. Folded intervals are durable, sorted, disjoint, and compositional; `[]` is wholly open and `[[1,-1]]` wholly folded. An active row's canonical body remains complete through log READ/FIND regardless of folded visibility. Rows and bodies persist, and classification changes still land when visibility is a no-op. Malformed targets, unsupported coordinate arity, and nonexistent exact coordinates fail at their owning boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1568
1664
 
1569
1665
  ### §jsonplurnk The Log's wire format
1570
1666
 
1571
- 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 visible content line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, 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 three body states are self-describing through field presence alone: a `body` field means open, `tokensBody` without `body` means folded (the value prices the OPEN), and neither means no canonical body; no `display` label exists. Two defaults are likewise field absence: `origin` is omitted for the worker's own model authorship (exactly as `source` absence means the owning worker), and `status` is omitted for a routine 200 on a non-SEND row — SEND always carries its submit code and every non-200 stays explicit. A partially hidden open row also carries `"folded":["<scope>",...]`; coordinate gaps in its body make the omission explicit without renumbering later lines. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. It leads each entry object; the remaining members follow in stable alphabetical order. A present authored operation annotation appears as `annotation`; its absence omits the field. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an automatic bounded projection differs from the visibility-selected 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. Every row's accounting: {§packet-token-accounting}.
1667
+ 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 visible content line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, 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 three body states are self-describing through field presence alone: a `body` field means open, `tokensBody` without `body` means folded (the value prices the OPEN), and neither means no canonical body; no `display` label exists. Two defaults are likewise field absence: `origin` is omitted for the worker's own model authorship (exactly as `source` absence means the owning worker), and `status` is omitted for a routine 200 on an ordinary row. SEND always carries its submit code, KILL keeps an explicit 200 so destructive completion is decisive, and every non-200 stays explicit. A partially hidden open row also carries `"folded":["<scope>",...]`; coordinate gaps in its body make the omission explicit without renumbering later lines. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. It leads each entry object; the remaining members follow in stable alphabetical order. A present authored operation annotation appears as `annotation`; its absence omits the field. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an automatic bounded projection differs from the visibility-selected 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. Every row's accounting: {§packet-token-accounting}.
1572
1668
 
1573
1669
  - §packet-token-accounting Every row reports its real weight so the packet self-reconciles against the budget: `tokensBody` is the projected body's nonzero weight whenever a canonical body would render (never `0` — a priceless OPEN is field absence), and `tokensActive` is the complete row's weight in the packet right now. The metadata share is derivable (`tokensActive − tokensBody` when open; `tokensActive` otherwise) and is never serialized — it feeds no curation decision. Thus FOLD removes the rendered body's weight while KILL removes `tokensActive`; on a folded row `tokensBody` previews the body share an OPEN would activate. The completed row, including its accounting field and framing, is measured to a fixed point. 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 state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1574
1670
 
@@ -1586,7 +1682,9 @@ The packet projects one actionable owner for each retrieval fact:
1586
1682
  | exact matcher FIND | compact `matchLocation` range | each row's locator/region; a regex or glob row also carries `matched`, the matched text | none |
1587
1683
 
1588
1684
  The compact range is `{ unit, total, requested: [first,last], returned?:
1589
- [first,last] }` ({§range-extent}); empty results omit `returned`. Transparent
1685
+ [first,last] }` ({§range-extent}); empty results omit `returned`. An empty result
1686
+ set satisfies any well-formed page: zero matches is the answer, a 200 with no items,
1687
+ never a 416 (#425 F9). Transparent
1590
1688
  coordinates let the model determine whether more material exists and choose
1591
1689
  its own next request, so packet metadata never prescribes `next`, `complete`,
1592
1690
  or `all`. FIND range cardinality replaces top-level `items`, `lines`, and
@@ -1600,17 +1698,17 @@ ordinary bounded bodies expose their displayed and complete chunk extents there.
1600
1698
 
1601
1699
  ### §turn-ops-entry The admitted turn program
1602
1700
 
1603
- §turn-ops-log-curation A source-backed turn preserves its **exact admitted Plurnk program** as an actionless log item in addition to the ordinary result row for every dispatched statement. `op` is null, `attrs.kind="turnOps"` identifies the item, `origin` is the turn producer, no target exists, `tx` is empty, and the source lives in `rx.content`, typed `text/vnd.plurnk`. Its exact address is the undecorated three-part coordinate `log:///<L>/<T>/<S>` because it is the turn program, not another operation. It is line-numbered and OPEN/FOLD/KILL-able like any log body. The worker-initialization `turnOps` is born OPEN because it is the worked orientation example; every other `turnOps`, including model inference and overflow recovery, is born FOLDED and remains available on demand. Log-KILL clears the `writableBy` gate for a model-authored item (Log's handler surface — kill only — keeps every other mutating op at 501). The shared executor writes exactly one after every admitted source-backed turn.
1701
+ §turn-ops-log-curation A source-backed turn preserves its **exact admitted Plurnk program** as an actionless log item in addition to the ordinary result row for every dispatched statement. `op` is null, `attrs.kind="turnOps"` identifies the durable type, `origin` is the turn producer, no target exists, `tx` is empty, and the source lives in `rx.content`, typed `text/vnd.plurnk`. Its canonical model-facing address appends the lowercase `/ops` leaf to its three-part coordinate. The packet does not duplicate that identity as `kind` metadata. It is line-numbered and READ/FIND/OPEN/FOLD/KILL-able like any active log body. The worker-initialization `turnOps` is born OPEN because it is the worked orientation example; every other `turnOps`, including model inference and overflow recovery, is born FOLDED and remains available on demand. Log-KILL clears the `writableBy` gate for a model-authored item and retires only its active projection under {§log-history-projection}; the exact program remains forensic history. Log's handler surface keeps every other mutating op at 501. The shared executor writes exactly one after every admitted source-backed turn.
1604
1702
 
1605
- §rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, and the exact latest rejected response. It is born durably FOLDED and projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
1703
+ §rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, the canonical model-facing `/attempt` leaf, and the exact latest rejected response. The packet does not duplicate that identity as `kind` metadata. It is born durably FOLDED and projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
1606
1704
 
1607
- - §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.
1705
+ - §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 complete `[start-end]` segment in any numeric coordinate slot selects that inclusive decimal interval; brackets elsewhere retain ordinary path-glob meaning. Every rendered row appends one canonical model-facing leaf: `/OP` for an operation, `/ops` for an admitted turn program, or `/attempt` for a rejected emission. The leaf names identity rather than adding a resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive leaf is authoritative and a disagreement resolves 404. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ`, `log:///**/ops`, and `log:///**/attempt` deliberately filter canonical leaves.
1608
1706
  - §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.
1609
1707
  - §log-curation-set-selection **Row selection and body scope are independent** — target/glob, optional body matcher, and optional ALL-tags filter compose by intersection into the affected row set. An optional `<L>` or `<SL,EL>` then intersects each selected canonical body; it never paginates or changes the selected set. Thus `## FOLD0 (log:///**/READ) <17,-1>` may change long READs and no-op on short ones while reporting every selected row in `matched`.
1610
1708
 
1611
- §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 folded intervals before and after, 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 with each before state as a collision guard. The authored program also survives verbatim in its `turnOps` item. 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.
1709
+ §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** and **renders exactly once** — in the packet after its turn, as its path, target, and status — then dissolves from the projection ({§curation-receipt-dissolves}): the actor sees its `200` or `204` at the one moment it decides whether to conclude or repeat, 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, and how a model that deferred its confirmation re-issued a KILL into the turn ceiling), and the log never accumulates housekeeping — a permanent receipt row would be a crumb that itself needs sweeping. Its exact selected target set, each target's active/folded state before and after, 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, projection changes, tag changes, and landed effects commit in one database statement with each before state as a collision guard. The authored program also survives verbatim in its `turnOps` item. 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.
1612
1710
 
1613
- §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 authored program survives in its `turnOps` item. 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.
1711
+ §curation-receipt-dissolves **Successful log-curation receipts dissolve.** A model-authored OPEN, FOLD, or KILL of a log item renders in exactly the packet immediately after its turn — path, target, and status, no body — and leaves the active projection once a later model turn has rows; history keeps the row, the exact active/folded transition for every target, and the authored `turnOps`. Nothing is left to curate: a receipt that dissolves is not a log item to sweep. A KILL of a log item retires the selected rows from the worker's active projection under {§log-history-projection}; it does not delete their execution history. The dissolving is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or another stored artifact retains its scheme-owned world or process semantics and stays visible. A killed exact coordinate resolves 404 in ordinary log operations; a well-formed broad selection with no active matches remains the 204 no-op of {§log-curation-folder-idiom}, and that 204 renders once like any dissolving receipt. Failed OPEN/FOLD/KILL render like every operation error and persist.
1614
1712
 
1615
1713
  ### §log-sensitive-request-evidence Durable request evidence
1616
1714
 
@@ -1620,10 +1718,11 @@ secret detection.
1620
1718
 
1621
1719
  | Surface | Durable rule |
1622
1720
  | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1623
- | Operation target | Each non-null URL username or password becomes `__redacted__`; every request-metadata value becomes the same marker while names, order, duplicates, and represented slot presence survive. `raw` is rebuilt from that projected representation. |
1624
- | COPY/MOVE destination | The nested destination target receives the identical projection. URI component columns derive from the projected primary target, so columns and `tx` cannot disagree. |
1721
+ | Operation target | Each non-null URL username or password becomes `__redacted__`; `raw` is rebuilt from that pure projected target. |
1722
+ | Scheme metadata modifier | Every present block becomes `__redacted__` wholesale; only ordered block count and represented-slot presence survive ({§scheme-metadata-modifier}). |
1723
+ | COPY/MOVE destination | The nested destination target receives the identical URL-credential projection. URI component columns derive from the projected primary target, so columns and `tx` cannot disagree. |
1625
1724
  | Query and authored body | Preserved exactly; they are authored content and URI identity, not structurally identifiable credential slots. |
1626
- | Parser failure | Preserves the structural diagnosis and source position without quoting request-metadata contents ({§path-request-metadata}). |
1725
+ | Parser failure | Preserves the structural diagnosis and source position without quoting scheme-metadata contents ({§scheme-metadata-modifier}). |
1627
1726
  | Client, fork, packet, and digest | Consume the stored projection; none owns a second redaction policy. |
1628
1727
  | Model-call evidence and source artifacts | `model_calls.response` under {§emission-admission}, `turnOps` under {§turn-ops-log-curation}, and `emissionAttempt` under {§rejected-emission-entry} remain exact forensic evidence and are the explicit exception. |
1629
1728
 
@@ -1640,8 +1739,9 @@ body: ResourceSelection (destination), signal: tags | null }`.
1640
1739
  2. Resolve destination path, channel, and optional text scope. Source and
1641
1740
  destination mimetypes must agree or the result is 415. Destination anchors
1642
1741
  resolve independently under {§line-anchors}.
1643
- 3. A scoped destination must already exist and is mutated through the
1644
- destination scheme's `editBatch`.
1742
+ 3. A partial scoped destination must already exist and is mutated through the
1743
+ destination scheme's `editBatch`. A complete-value destination scope on an
1744
+ absent resource is creation under {§fs-write-surface}.
1645
1745
  4. An unscoped destination writes only its selected channel. Existing other
1646
1746
  channels survive.
1647
1747
  - §copy-conflict-409 Different content in that channel is 409.
@@ -1687,7 +1787,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
1687
1787
 
1688
1788
  AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal: tags | null, lineMarker? }`.
1689
1789
 
1690
- - §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.
1790
+ - §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 — in every spelling: a `**` glued to a name (`**.go`, `src/**.ts`) is matched as `**/*.go` / `src/**/*.ts`, never demoted to a one-level `*` the way a native matcher reads it (run67, 2026-08-29: a whole-repository search silently confined to the root). 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.
1691
1791
  - An exact target resolves to the same canonical `(scheme, authority, pathname)` identity
1692
1792
  as READ, entry CRUD, and any preceding `prepareFind()`. URI authorities are
1693
1793
  identity-bearing: `https://example.com/page` queries
@@ -1791,16 +1891,22 @@ the loop continue; repeated offenses terminate through the engine's 500.
1791
1891
  | Idle turn | An engine-rail error row with the corrective disposition | One strike |
1792
1892
  | Refused disposition | The final SEND's 409 row with its exact Problem Detail | One strike |
1793
1893
 
1894
+ Executor results are evidence, never strikes: a command's nonzero exit — surfaced
1895
+ as its completion READ ({§exec-stream}) or read by the model from the stream —
1896
+ carries an `executor/*` problem identity and does not enter the streak. Structural
1897
+ violations (a missing PLAN or terminal SEND, an operation dropped by a parse
1898
+ failure) do strike: six in a row is a degenerated run.
1899
+
1794
1900
  - §send-target-recipient **A SEND target is a recipient.** A model's directed SEND
1795
1901
  addresses a worker (`## SEND0 (worker://<name>)`), an outbound agent (`a2a://`),
1796
1902
  or a scheme that implements SEND (an `https://` POST); with `[410]` it names a
1797
1903
  resource to delete. A SEND to a scheme the model may not write (the prompt, the
1798
- log) is refused 400 `send-target-not-a-recipient` — the detail says the reply to
1799
- the active prompt carries no target and the recovery names the recipient form —
1800
- never the writer rule, which is true and teaches nothing (a model answering
1801
- `(prompt:///…)` was striking out on 403s). A scheme that does not implement SEND
1802
- answers 501 with the same recovery.
1803
- - §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.
1904
+ log) is refused 400 `send-target-not-a-recipient`, never the unrelated writer
1905
+ rule. The detail states only that the addressed scheme is not a recipient;
1906
+ neutral recovery distinguishes targetless replies from directed SEND without
1907
+ guessing which one was intended. A scheme that does not implement SEND
1908
+ answers its ordinary factual 501 without grafting a guessed recovery onto it.
1909
+ - §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. **An empty `[102]` while the worker holds a live stream or child is a mis-spelled wait, not idleness**: the engine parks the turn as `[202]` — the same live-work predicate the `[200]` gate uses, so the shift never disagrees with the orientation the model reads — records the SEND as `202` with the correction in that row's annotation (a park drops transient notices; the row survives the wake); no strike. With nothing in flight the idle-turn 409 stands — it is the deterministic recovery for that case.
1804
1910
  - §send-premature-terminate **Premature terminate — the pending set.**
1805
1911
  A model's completion claim is gated by one rule: *nothing pending may be silently
1806
1912
  discarded*. Pending work has two states: **live obligations** (open
@@ -1813,7 +1919,10 @@ the loop continue; repeated offenses terminate through the engine's 500.
1813
1919
  retrieval members are unchanged. The set is judged at the disposition's own dispatch, after
1814
1920
  earlier operations in the emission. `[200]` over any member is refused 409
1815
1921
  and the loop continues; every refusal strikes uniformly, including a
1816
- retrieval-only refusal. The pending kind changes the corrective message, not
1922
+ retrieval-only refusal. Its Problem reports only the bounded pending kinds
1923
+ `streams`, `workers`, `receipts`, `failed-stream-results`, and
1924
+ `worker-results`; it never embeds commands, stream handles, result bodies, or
1925
+ a presumed recovery. The pending kind changes the factual Problem class, not
1817
1926
  rail accounting. `[499]` deliberately abandons regardless.
1818
1927
  - §send-administrative-terminal **An administrative terminal closes its own
1819
1928
  transaction.** A client, plugin, or `_plurnk` operation program runs in its
@@ -1842,12 +1951,22 @@ a relative target against the directory the command would run in — the project
1842
1951
  root, or the shell's own cwd when the workspace has none — and inspects it
1843
1952
  before anything spawns: a directory becomes the working directory, a file is the
1844
1953
  script; anything else is refused `400 target-not-found`, naming that directory
1845
- and stating that a command belongs in the body. The started receipt always
1846
- names the working directory. The EXEC `(path)` is one of cwd, script, or tool
1954
+ and giving the applicable accepted form without inferring what the model meant.
1955
+ When the target is a registered tool of another runtime, recovery gives that
1956
+ tool's exact runtime-qualified invocation; otherwise it distinguishes an existing
1957
+ directory/script target from a targetless shell-command body. A non-file resource
1958
+ target that cannot be read keeps the owning READ's failure identity (#163) and states
1959
+ the slot contract in its recovery — the resource is the program and the body its stdin;
1960
+ a command belongs beneath a targetless heading — without guessing which was meant (#425). The started receipt always
1961
+ names the working directory only when it is not the project root, and then in the
1962
+ model's own project-relative form ({§fs-namespace}: the root is the model's `/`, so it
1963
+ is never rendered, and no receipt or Problem carries a host-absolute path — the
1964
+ batch of 2026-08-29 showed the absolute `cwd` copied back into the target slot as
1965
+ `(cwd: /host/path)`). The EXEC `(path)` is one of cwd, script, or tool
1847
1966
  name — the runtime's declaration decides which (interpreters: cwd or script;
1848
1967
  tool families: tool name) — and a command is never a target. The default shell
1849
- is taught as the bare `EXEC` with `(.)`; `[sh]` and `[bash]` remain the explicit
1850
- forms.
1968
+ is taught as targetless bare `EXEC`; `[sh]` remains the explicit form, and an
1969
+ authored directory target remains an optional cwd override.
1851
1970
 
1852
1971
  | Declared target kind | Authored target | Canonical effect target | Executor realization |
1853
1972
  | -------------------- | --------------------------------------- | ----------------------- | --------------------------------------------------------- |
@@ -1899,7 +2018,7 @@ Loop-flag authority follows the selected runtime's declaration:
1899
2018
  | Absent, `literal`, local `path`, or local `resource` | `exec` |
1900
2019
  | Non-file `resource` | `exec` and the addressed source scheme |
1901
2020
 
1902
- Worker and runtime-stream authorities, query, fragment, request metadata, and
2021
+ Worker and runtime-stream authorities, query, fragment, the scheme metadata modifier, and
1903
2022
  every other component of a `resource` address retain their owning READ
1904
2023
  semantics. A failed source READ is preserved as the proposal-application
1905
2024
  failure. A successful READ with no string representation is refused 422; an
@@ -1918,9 +2037,10 @@ Worker Functionality providers may atomically overlay additional names under
1918
2037
  {§module-worker-capabilities}; a name has one owner within a worker, while
1919
2038
  independent workers may use the same name. An absent or empty tag selects
1920
2039
  `sh`; a non-empty tag selects exactly that registered executable tool. Unknown
1921
- tags are refused 501 with direction to use only the advertised catalogue or
1922
- put a complete command in bare `EXEC`; they are never reinterpreted as shell
1923
- command words. An unavailable runtime is also 501 and carries the probe
2040
+ tags are refused 501 with the advertised catalogue and are never reinterpreted
2041
+ as shell command words. The common mistaken `[shell]` alias is narrowly told to
2042
+ omit that signal for the default shell; arbitrary unknown tags receive no guessed
2043
+ alternative intent. An unavailable runtime is also 501 and carries the probe
1924
2044
  `detail`.
1925
2045
 
1926
2046
  For a family runtime, `ExecutorRegistry.toolRegistry(tag, workerId)`
@@ -1932,8 +2052,9 @@ catalogue.
1932
2052
  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}
1933
2053
 
1934
2054
  **Timeout and poll — `<T,P>` on the `<L>` slot (grammar 0.74.20).** EXEC
1935
- repurposes the line-marker slot as `<timeout, poll>` in **seconds**, the same
1936
- unit as `stream.seconds` in the catalog.
2055
+ repurposes the line-marker slot as `<timeout, poll>` in **minutes** — agentic
2056
+ latencies make a sub-minute horizon a trap — converted at the parse boundary to the
2057
+ catalog's internal `stream.seconds`. The SEND `[202] <T>` wait horizon is minutes too.
1937
2058
 
1938
2059
  §exec-timeout `T` (`mark[0]`) caps the spawn's lifetime. At `T>0` the service
1939
2060
  aborts it — a bounded reap, polite signal then SIGKILL after
@@ -1947,7 +2068,7 @@ its terminal output surfaces born-OPEN like any close ({§exec-stream}).
1947
2068
  §exec-poll `P` (`mark[1]`) is the **poll cadence**, stored on the subscription.
1948
2069
  While the loop is blocked on a SEND signal `202` wait for that stream, the daemon arms
1949
2070
  a per-worker timer for the tightest open poll cadence and resumes the blocked
1950
- loop every P seconds, floored by `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS` so it cannot tick
2071
+ loop every P minutes, floored by `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS` so it cannot tick
1951
2072
  faster than the optimistic settlement scale, to inspect progress. It does **nothing while the
1952
2073
  loop is active** because ambient stream deltas already surface progress. An
1953
2074
  open stream without `P` uses exponential backoff
@@ -1978,10 +2099,12 @@ may use a semantic Worker name there, but the private numeric id never appears
1978
2099
  in a URI or packet. `plurnk` and `commons` are reserved Workers, and `~` is the
1979
2100
  current-Worker sigil; none can be minted by a spawn or client.
1980
2101
 
1981
- §stream-owner-scoped **Capability streams are owner-scoped.** Concurrent workers' stream coordinates are loop-relative and IDENTICAL (every worker's first loop is sequence 1), so the entry identity keys on the owner and identical coordinates across workers are distinct rows. The address's authority names the owner: **empty = the calling worker** — your own streams need no qualifier, so a fan-out sibling's output can never surface under your READ — and a **named authority** reaches that worker's streams gated by ancestry (the reader is the owner or an ancestor; oversight flows down the tree, unknown-or-unpermitted resolves 404 with no existence leak). KILL stays self-only — a parent controls a child through the worker lifecycle, never by reaching into its streams. The storage pathname stays the bare loop coordinate; the owner rides the column, so nothing model-facing carries a worker id.
2102
+ §stream-owner-scoped **Capability streams are owner-scoped.** Concurrent workers' stream coordinates are loop-relative and IDENTICAL (every worker's first loop is sequence 1), so the entry identity keys on the owner and identical coordinates across workers are distinct rows. The address's authority names the owner: **empty = the calling worker** — your own streams need no qualifier, so a fan-out sibling's output can never surface under your READ — and a **named authority** reaches that worker's streams for any worker of the workspace (the parent designs the topology by what it names to whom; the engine imposes none, #394; an unknown name resolves 404). A child is told its parent's name in its packet (`parent-worker`). KILL stays self-only — a parent controls a child through the worker lifecycle, never by reaching into its streams. The storage pathname stays the bare loop coordinate; the owner rides the column, so nothing model-facing carries a worker id. A stream 404 never discloses existence, but it names the address space: the coordinate shape, the unqualified self, the descendant-by-name form, and that a tool's own ids are arguments, not addresses.
1982
2103
 
1983
2104
  §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.
1984
2105
 
2106
+ §workspace-auto-name **Workspace auto-names are five anchor-alphabet characters.** A `workspace.create` without a name draws five characters from the {§line-anchors} alphabet `0-9A-Za-z` (uniformly, from a cryptographic source), redrawing on the astronomically rare collision. No prefix, timestamp, or origin marker: a name never encodes where a workspace came from, so nothing can grow load-bearing on it.
2107
+
1985
2108
  §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.
1986
2109
 
1987
2110
  §effect-policy-tunable **Effect admission is deployment-tunable.** The default
@@ -2000,7 +2123,22 @@ two states and no others:
2000
2123
  | state | what the model receives |
2001
2124
  |---|---|
2002
2125
  | active | nothing in the Log. The `## Child Streams` pointer names the stream with each channel's size and its growth since the last packet ({§child-orientation}); the model READs any range it wants. |
2003
- | terminal | ONE `origin=_plurnk` READ at `<runtime>:///<coord>#<channel>`, born OPEN, that is exactly a markerless READ of the channel — its first page ({§read-selection-projection}: lines 1–16, the whole channel when it fits, the channel's own mimetype), the `range` extent, and the terminal status and Problem. |
2126
+ | terminal | ONE `origin=_plurnk` READ at `<runtime>:///<coord>#<channel>`, born OPEN, that is exactly a markerless READ of the channel — its first page ({§read-selection-projection}: lines 1–16, the whole channel when it fits, the channel's own mimetype), the `range` extent, terminal status and Problem, `terminal: true`, any producer-supplied integer `exitCode`, and `source: log:///<coord>/EXEC` linking the causal invocation. The packet renders that address under `stream`, exactly as the invocation row links its output, never under `target`: a stream is observed, not a slot to author. |
2127
+
2128
+ §exec-concurrency **Bounded admission per workspace (#389).** At most
2129
+ `PLURNK_SERVICE_EXEC_CONCURRENCY` executions run at once in one workspace (shipped `12`;
2130
+ `-1` unbounded); the scope is the workspace, so neither delegation nor later turns
2131
+ bypass it and no other workspace can starve it. Every admitted EXEC still creates its
2132
+ entry, channels, and open subscription before its receipt returns, so queued work is
2133
+ cancellable, restart-reconcilable, completion-gated, and observed through the ordinary
2134
+ stream mechanics ({§exec-stream}). The receipt tells the truth once and never rewrites
2135
+ it: an immediate slot is `200 { outcome: "started" }`; delayed work is
2136
+ `202 { outcome: "queued", executionsAhead, concurrency }`, and the channel stays
2137
+ `active` in the existing live sense — output growth and terminal settlement are the
2138
+ current truth. Admission is FIFO within the workspace; queue residence does not consume
2139
+ the execution timeout; a KILL while queued never invokes the executor and closes the
2140
+ stream through the normal 499 path. The scheduler is the EXEC scheme's; the knob is the
2141
+ service's ({§operator-config}), fail-hard on any other value.
2004
2142
 
2005
2143
  §exec-stream-page **An unrequested delivery never exceeds the retrieval page.** The
2006
2144
  terminal observation is the same page a markerless READ returns, whatever the
@@ -2015,7 +2153,8 @@ to the model — by the Child Streams pointer while active, by the terminal
2015
2153
  observation at close — so the pointer can state growth and no partial document
2016
2154
  or record ever reaches the model. The terminal observation and its cursor
2017
2155
  transition commit atomically; a terminal state with an empty channel still
2018
- produces one bodyless conclusion row. OPEN, FOLD, or KILL may curate
2156
+ produces one bodyless conclusion row whose terminal fact, causal EXEC link, and
2157
+ available exit code make completion explicit without invented narration. OPEN, FOLD, or KILL may curate
2019
2158
  that log row without rewinding the cursor or publishing the terminal result
2020
2159
  again; the exact terminal result and channel content remain READable at the
2021
2160
  stream address. Every READ then obeys {§body-projection} and therefore renders
@@ -2055,7 +2194,7 @@ stream cannot fall through an internal `exec`-only query. {§stream-control}
2055
2194
 
2056
2195
  §proposal-outcome-terse-error A caller-supplied `outcome` overrides the default. On an **accept** it stays forensics-only; a **non-accept** carries it as the `rx`'s terse `error` token (`write_failed` / `rejected` / `timeout` — one word, never prose), because "the action didn't occur" without the mechanical why leaves the model acting on a phantom success (the fan-out dead-park: an ENOENT apply rendered as a mute 400).
2057
2196
 
2058
- §proposal-proposed-hidden **A proposed row is invisible until it resolves.** A `state='proposed'` / 202 row is withheld from the `log` section; it surfaces only after resolution, carrying its terminal status — the model sees outcomes, never pending proposals.
2197
+ §proposal-proposed-hidden **A proposed row is invisible until it resolves.** A `state='proposed'` / 202 row is withheld from both packet materialization and `log/entry`; it surfaces exactly once after resolution, carrying its terminal status — models and clients see outcomes, never pending proposals.
2059
2198
 
2060
2199
  ### §proposal-projection One durable proposal, one client projection
2061
2200
 
@@ -2067,7 +2206,7 @@ Core derives the contracts-owned `ProposalProjection` from the durable proposed
2067
2206
  | `target` | canonical `{ scheme, authority, pathname }` from `attrs.proposalTarget` for staged COPY/MOVE, otherwise the log row target |
2068
2207
  | `body` | proposed operation result `rx.body`; absent means the empty review body |
2069
2208
  | `attrs` | proposed log row `attrs` object |
2070
- | `flags` | validated persisted loop flags expanded over contracts-owned defaults |
2209
+ | `policy` | validated complete persisted loop policy |
2071
2210
  | `disposition` | {§proposal-disposition}; the same value drives automatic settlement and client presentation |
2072
2211
 
2073
2212
  Workspace scope remains the event envelope / seam argument ({§notifications-envelope-carries-workspaceid}); it is not forged into `ProposalProjection`. Malformed durable JSON, target metadata, result envelopes, loop policy, or final projection fails at core with its cause; after insertion, core terminalizes that row as a 500 `policy_failed` before propagating the internal failure, so no waiter or durable stopped world is orphaned.
@@ -2091,15 +2230,15 @@ removes ownerless rows without fabricating cancellation, payload, or replay.
2091
2230
 
2092
2231
  ### §proposal-disposition Settlement authority and precedence
2093
2232
 
2094
- `ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The decision table is complete and ordered:
2233
+ `ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The persisted loop policy determines it exactly:
2095
2234
 
2096
- | `auto` | `noProposals` | Disposition |
2097
- | ------ | ------------- | ---------------------------------------- |
2098
- | true | any | loop accept |
2099
- | false | true | loop reject, outcome `no_review_channel` |
2100
- | false | false | client |
2235
+ | `policy.proposals` | Disposition |
2236
+ | ------------------ | ---------------------------------------- |
2237
+ | `review` | client |
2238
+ | `accept` | loop accept |
2239
+ | `reject` | loop reject, outcome `no_review_channel` |
2101
2240
 
2102
- Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination. Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
2241
+ Capability admission precedes this decision, so proposal disposition cannot grant a denied capability. Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
2103
2242
 
2104
2243
  ---
2105
2244
 
@@ -2137,6 +2276,7 @@ Model sees lifecycle events in the `log` section per turn.
2137
2276
  ### §stream-control Stream control and writes
2138
2277
 
2139
2278
  - **Cancel:** `## SEND0 [499] (https://feed.example/x)` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
2279
+ - **Kill:** `## KILL0 (sh:///1/2/3)` — the model terminates its own runtime stream. This is stream control, not a write: the output scheme's `writableBy` never gates it, `Exec.kill` scopes the address to the caller ({§stream-owner-scoped}), and a finished stream answers 410 under its own tag. A queued execution ({§exec-concurrency}) is cancelled the same way and never enters its executor.
2140
2280
  - **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.
2141
2281
  - **Other stream write:** `## SEND0 [200] (…)` remains scheme-defined, including exec stdin.
2142
2282
 
@@ -2257,15 +2397,15 @@ freshness remains the owning family's concern.
2257
2397
  | Schemes | `@plurnk/plurnk-schemes` | `@plurnk/plurnk-schemes-http` |
2258
2398
  | Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format leaves. |
2259
2399
  | | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format leaves. |
2260
- | | | Fixed `embeddings` artifact. All names use the `@plurnk/plurnk-mimetypes-*` prefix. |
2261
- | Executors | `@plurnk/plurnk-execs` | `common`, `git`, `jq`, `sqlite`, and `wasm` leaves under the `@plurnk/plurnk-execs-*` prefix. |
2400
+ | | | Fixed `embeddings` artifact, including exact counters for its built-in profiles. All names use the `@plurnk/plurnk-mimetypes-*` prefix. |
2401
+ | Executors | `@plurnk/plurnk-execs` | `common`, `jq`, and `sqlite` leaves under the `@plurnk/plurnk-execs-*` prefix. |
2262
2402
 
2263
- The independently published `application-pdf` handler and `tokenizers`
2403
+ The independently published `application-pdf` handler and general `tokenizers`
2264
2404
  artifact are opt-in leaves. Installing either beside the service admits it
2265
- through ordinary package discovery without changing the service manifest. The
2266
- default local embedding artifact owns the exact counter for its own model;
2267
- remote embedding deployments install `tokenizers` when their provider does not
2268
- supply an exact counter.
2405
+ through ordinary package resolution without changing the service manifest.
2406
+ The service-owned embedding artifact owns exact counters for its built-in local
2407
+ and hosted profiles; a custom profile may resolve another vocabulary through
2408
+ the optional general artifact.
2269
2409
 
2270
2410
  **Providers:** `@plurnk/plurnk-providers` resolves the Models.dev catalog,
2271
2411
  operator declarations, local adapters, and finally installed AI SDK provider
@@ -2303,7 +2443,7 @@ service manifest edit.
2303
2443
  - Backpressure caps — none ({§stream-constraints}).
2304
2444
  - Stream cancel — SEND signal `499` ({§stream-control}).
2305
2445
  - Delete — `KILL` (entry-KILL, the canonical delete, {§move}); SEND signal `410` also deletes as a side-effect ({§send-dispatch}).
2306
- - §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.
2446
+ - §loop-policy-effective-read Per-loop policy — `loops.policy` persists one complete immutable `LoopPolicy`; every runtime policy read validates that snapshot 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.
2307
2447
  - Default-channel wire rendering — {§channel-selection}.
2308
2448
 
2309
2449
  ---
@@ -2362,12 +2502,15 @@ Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-
2362
2502
  |-------------------------------------------------------------|---------|---------|
2363
2503
  | `PLURNK_SERVICE_DB_PATH` | `$XDG_DATA_HOME/plurnk/plurnk.db` | SQLite file path; an explicit non-empty value overrides the derived default. |
2364
2504
  | `PLURNK_HOST` | `127.0.0.1` | Bind address for the listener. Local-only by default. |
2365
- | `PLURNK_PORT` | `3044` | TCP port for THE client surface — the AG-UI+ listener (the plurnk-agui plugin module binds it at boot). Production is single-listener. |
2366
- | §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | `1` | Hard service ceiling: only `1` admits Git membership, status, branch batching, and `git`/`isogit` executors; every other value denies them before executor registration or packet teaching. |
2505
+ | `PLURNK_PORT` | `1066` | TCP port for THE client surface — the AG-UI+ listener (the plurnk-agui plugin module binds it at boot). Production is single-listener. |
2506
+ | §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | `1` | Hard service ceiling: only `1` admits Git membership, status, and branch batching; every other value denies them. |
2367
2507
  | §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | `root` | Hard file-creation ceiling: `none < root < namespace`. `none` denies new filesystem files, `root` admits only paths inside `project_root`, and `namespace` also admits canonical outside-root paths. Existing-member writes are unaffected. |
2508
+ | `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | `104857600` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
2368
2509
  | `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator inference-turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts completed model/inference turns cumulatively across every `202` park/resume; `_plurnk`, client, and plugin turns remain chronology but consume none of this allowance. |
2369
2510
  | `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). |
2370
2511
  | §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}). |
2512
+ | `PLURNK_SERVICE_PROVIDER_RECOVERY` | `900000` | ms a turn keeps re-issuing its provider call after a recoverable provider failure before the loop parks ({§provider-recovery}); `0` parks at once. |
2513
+ | `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | `5000` | First recovery delay (ms); doubles per failure, capped at twelve times itself ({§provider-recovery}). |
2371
2514
  | `PLURNK_SERVICE_MAX_STRIKES` | `6` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
2372
2515
  | `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. |
2373
2516
  | `PLURNK_SERVICE_PREVIEW_LINES` | `16` | Maximum lines in an ordinary bounded log-body projection ({§body-projection}). |
@@ -2380,6 +2523,8 @@ Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-
2380
2523
  | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
2381
2524
  | `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | `32768` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
2382
2525
  | `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}). |
2526
+ | `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` | `none` | Ceiling for a model's `members` definitions in the lattice `none < root < namespace`; `none` refuses every model definition ({§members-model-scope}). |
2527
+ | `PLURNK_SERVICE_EXEC_CONCURRENCY` | `12` | Executions admitted at once per workspace; the rest queue FIFO with `202 queued` receipts; `-1` unbounded ({§exec-concurrency}). |
2383
2528
  | `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}). |
2384
2529
  | §operator-config-worker-warm `PLURNK_SERVICE_WORKER_WARM_MS` | `900000` | Milliseconds a lease-free worker Functionality snapshot remains warm; `0` cools without grace and `-1` disables time-based cooling ({§module-worker-residency}). |
2385
2530
  | `PLURNK_SERVICE_WORKER_WARM_MAX` | `2` | Maximum lease-free worker Functionality snapshots retained process-wide; `0` retains none and `-1` disables the idle-LRU bound ({§module-worker-residency}). |
@@ -2407,8 +2552,8 @@ instead of a user's boot, and a dead knob cannot ship.
2407
2552
 
2408
2553
  | Owner | Configuration |
2409
2554
  |---|---|
2410
- | `.env.test` | Safe default model selection and universal real-model gate posture; no alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
2411
- | Live/demo scripts | The repository personality path and runner topology. |
2555
+ | `.env.test` | Safe default model selection and universal real-model gate posture, including the bundled embedder (an ambient operator embedding route never becomes a gate dependency); no alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
2556
+ | Live/demo scripts | The repository policy path and runner topology. |
2412
2557
  | Benchlets | Their snapshotted policy, workspace restrictions, and task-specific exceptions; direct env wins over the profile. |
2413
2558
  | Operator env/shell | Model alias declarations and explicit selection overrides, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
2414
2559
  | `test/setup.ts` | Mock-only alias, envelope, resource, storage, and isolation fixtures; unit/integration never consume the real-model profile. |
@@ -2447,7 +2592,7 @@ boundary. Operator-arcane knobs stay environment-only.
2447
2592
  | `settings.git` | Boolean | Tightening denial {§operator-config-workspace-git} |
2448
2593
  | `settings.fileCreateScope` | `none`, `root`, or `namespace` | Tightening ceiling {§operator-config-workspace-file-create-scope} |
2449
2594
  | `settings.client` | Nonempty string | Stable self-identification {§client-metadata} |
2450
- | `settings.execs` | Record of policy-key to string | Subtractive executor layer {§operator-config-workspace-execs} |
2595
+ | `settings.capabilities` | `CapabilityPolicy` | Subtractive capability layer {§operator-config-workspace-capabilities} |
2451
2596
 
2452
2597
  The composition families remain distinct so one setting's semantics never
2453
2598
  leak into another.
@@ -2462,22 +2607,17 @@ leak into another.
2462
2607
  workspace: a client tightens the runaway-op guard and never raises it past
2463
2608
  the operator's.
2464
2609
  - §operator-config-workspace-max-commands-floor The cap bounds *actions* only.
2465
- PLAN (complete current Plan) and the final disposition `SEND` (`102`, `200`, `202`,
2610
+ PLAN and the final disposition `SEND` (`102`, `200`, `202`,
2466
2611
  `300`, or `499`) are never counted and always dispatch, so `0` is a valid
2467
2612
  floor — the tightest — admitting a plan and disposition with zero actions.
2468
2613
  - §operator-config-workspace-git `settings.git` (`false`) **denies** git for the workspace (`PLURNK_SERVICE_GIT_ALLOWED` AND workspace) — the client opts its workspace out of git membership and working-tree status; it can never re-enable git past the operator's service-wide lockout.
2469
2614
  - §operator-config-workspace-file-create-scope `settings.fileCreateScope` narrows `PLURNK_SERVICE_FILE_CREATE_SCOPE` by the ordered lattice `none < root < namespace`; a workspace may disable creation or confine a namespace-enabled service to its root, but never widen the operator's ceiling. Unknown service values fail configuration validation and unknown workspace values fail `workspace.create`.
2470
- - §operator-config-workspace-execs `settings.execs` is a workspace-stable
2471
- snapshot of one `Record<string, string>` policy layer using
2472
- {§executor-policy}. Keys are matched case-insensitively and must be
2473
- `PLURNK_EXECS_ONLY` or `PLURNK_EXECS_<canonical-runtime-tag>`; MCP connection
2474
- configuration and non-string values are rejected. The boot-discovered
2475
- effective workspace registry is authoritative and the settings layer only
2476
- intersects it: settings cannot register or re-enable a runtime. A canonical
2477
- key for a currently absent tag is accepted as inert policy and applies if a
2478
- worker Functionality provider later publishes that tag. Dispatch and
2479
- model-facing tool-resource materialization use the same registered-set intersection and policy
2480
- predicate, so a workspace-disabled tag is neither executable nor taught.
2615
+ - §operator-config-workspace-members-model-scope `settings.membersModelScope` narrows `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` by the same lattice; a workspace may refuse the model's definitions entirely under a permissive service ({§members-model-scope}).
2616
+ - §operator-config-workspace-capabilities `settings.capabilities` is one
2617
+ workspace-stable `CapabilityPolicy` layer in {§capability-admission}. It may
2618
+ narrow any registered operation, scheme, runtime, tool, access class, or
2619
+ trait through the canonical `only`/`deny` selectors; it cannot register a
2620
+ capability or restore one removed by the service layer.
2481
2621
 
2482
2622
  Feature-flag bools use `process.env.X === "1"` exactly — never `=== "true"`.
2483
2623
 
@@ -2499,12 +2639,13 @@ names, request validation, discovery result, and event projection.
2499
2639
 
2500
2640
  ```mermaid
2501
2641
  flowchart LR
2642
+ bind["Host may pre-bind client-interface listener<br/>unready"] --> register
2502
2643
  register["Daemon.registerModule"] --> setup["module.setup(ModuleSetupSeam)"]
2503
2644
  setup --> capabilities["Register static capabilities,<br/>workspace activators, and actions"]
2504
2645
  capabilities --> ready["Process-wide schemes ready"]
2505
2646
  ready --> recovery["Reconcile durable lifecycle"]
2506
2647
  recovery --> start["module.start(ApplicationPort)"]
2507
- start --> interface["Module-owned listener<br/>and client protocol"]
2648
+ start --> interface["Module-owned client protocol<br/>ready"]
2508
2649
  recovery -->|durable workspace work| demand["First workspace demand"]
2509
2650
  interface -->|client workspace work| demand
2510
2651
  demand --> lease["Acquire capability residency"]
@@ -2522,14 +2663,19 @@ flowchart LR
2522
2663
 
2523
2664
  Every registered module's `setup` runs in registration order before any
2524
2665
  module's `start`. Core then readies process-wide schemes, reconciles durable
2525
- lifecycle, and starts modules in registration order. Persisted workspaces with
2666
+ lifecycle, and starts modules in registration order. The production
2667
+ client-interface module may already own its socket under
2668
+ {§startup-listener-admission}; its `start` activates request handling without
2669
+ rebinding. Persisted workspaces with
2526
2670
  no durable work stay passive until first demand; activation publishes their
2527
2671
  complete capabilities and documentation before the demanding operation
2528
2672
  proceeds. `setup` is the readiness boundary for every capability registered
2529
- with Core: recovery may demand a workspace provider before `start`. `start`
2530
- opens module-owned exterior ingress only after recovery, so no registered
2531
- capability may depend on it. Shutdown begins started and self-closing module
2532
- closure in reverse order and surfaces aggregated close failures.
2673
+ with Core: recovery may demand a workspace provider before `start`. For a
2674
+ pre-bound client interface, requests remain unavailable until `start`; every
2675
+ other module opens its module-owned exterior ingress only after recovery. No
2676
+ registered capability may depend on exterior ingress. Shutdown begins started
2677
+ and self-closing module closure in reverse order and surfaces aggregated close
2678
+ failures.
2533
2679
 
2534
2680
  §module-discovery **Third-party daemon-module composition is manifest
2535
2681
  discovery.** A package declares `plurnk: { kind: "module", module:
@@ -2650,6 +2796,11 @@ accepted model proposal converge on the same coordinator method; no family
2650
2796
  invents a third management grammar, configuration path, proposal policy, or
2651
2797
  hotload mechanism.
2652
2798
 
2799
+ Problem retryability is never inferred from numeric status. A coordinator
2800
+ failure names `retryable` only when its owning condition establishes whether an
2801
+ identical automatic replay is valid; in particular, absent Worker residency
2802
+ requires activation and is non-retryable as submitted.
2803
+
2653
2804
  | Verb | Common contract |
2654
2805
  |---|---|
2655
2806
  | `list` | Project every definition with its origin, desired enabledness, and current state — `disabled`, `active`, `unavailable` with its exact Problem, or `authorization-required` — without exposing credentials. |
@@ -2663,7 +2814,9 @@ hotload mechanism.
2663
2814
  declares its family (the action segment and EXEC tag), its one namespace owner,
2664
2815
  the exact definition schema one `add` accepts, its service-contributed
2665
2816
  definitions with their default enabledness, inert discovery, admission of an
2666
- authored definition, two-phase preparation of the enabled set, and teardown.
2817
+ authored definition — told whether a client action or a model operation authored it, so a
2818
+ family may bound the model's authority ({§members-model-scope}) — two-phase preparation of
2819
+ the enabled set, and teardown.
2667
2820
  Preparation returns the family's runtimes, its generated documents, one outcome
2668
2821
  per enabled alias, and a snapshot with `commit`/`abort`; the coordinator
2669
2822
  never tears down a previous snapshot behind the adapter — it commits after a
@@ -2713,8 +2866,12 @@ family per Worker.** Every activated Worker publishes, for each registered
2713
2866
  family, one executor tagged with the family name whose registered targets are
2714
2867
  exactly the six verbs; its documents render through
2715
2868
  {§tools-resource-materialization} like every family, so the model learns the
2716
- manager from `_plurnk/skills/plurnk/<family>.md` and never from hand-written
2717
- teaching. `list` and `discover` are `read` effects and run ungated; `add`,
2869
+ manager from `_plurnk/plurnk/<family>.md` and never from hand-written
2870
+ teaching. That document lists the six verbs in lifecycle order and teaches the
2871
+ definition from the family's own schema — one exact `add` example and a table of
2872
+ every field with its type, requirement, and meaning — and carries the family's own
2873
+ `discover` contract when the generic one does not fit; the model composes an `add`
2874
+ from the document alone, without a probe. `list` and `discover` are `read` effects and run ungated; `add`,
2718
2875
  `enable`, `disable`, and `remove` are `host` effects and propose through
2719
2876
  the ordinary Exec proposal lifecycle. A verb's JSON outcome streams into the
2720
2877
  family's output entry. `ExecArgs` carries no Worker identity, which is why
@@ -2745,7 +2902,7 @@ Core's behavior behind them.
2745
2902
  | §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. |
2746
2903
  | §client-interaction-list Client interactions | `pendingClientInteractions(workspaceId)` | Intersects durable interaction rows with their live operation waiters and returns the contracts-owned projection; a row alone is not a resumable interaction. |
2747
2904
  | §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution)` | Validates and delivers one resolved payload or cancellation. Unknown, ownerless, and already-resolved identities fail before affecting an operation. |
2748
- | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?, flags?, openPaths?, selector?, childSelector? })` | 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`. A trusted adapter may identify the prompt's causal actor with one canonical `source`; ordinary clients cannot author it through their protocol surface. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
2905
+ | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?, policy?, openPaths?, selector?, childSelector? })` | Validates a model worker and complete loop policy, persists it with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. A trusted adapter may identify the prompt's causal actor with one canonical `source`; ordinary clients cannot author it through their protocol surface. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
2749
2906
  | §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)`; `cancelWorker({ workspaceId, workerId, reason? })` | `cancelDrain` begins durable structured cancellation and reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. The ownership-bounded `cancelWorker` awaits that same tree cancellation and stream reap, so an exterior protocol can project the settled durable result without polling or fabricating state. |
2750
2907
  | §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, functionalityWorkerId, statements })` | Dispatches already-parsed grammar statements as one client action in one administrative loop in the client worker, executing in the attached Worker's Functionality ({§actor-boundary-attached-functionality}). Every statement is an ordered client/operation turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep its turn, loop, and action promise open until resolution. Core exposes no per-op method family. |
2751
2908
  | Client observation | `look({ workspaceId, workerId, functionalityWorkerId, statement })` | Runs an already-parsed READ through the full resolver in the attached Worker's Functionality without a log row. A non-READ statement is rejected ({§op-look}). |
@@ -2754,13 +2911,12 @@ Core's behavior behind them.
2754
2911
  | Providers | `listProviders()` | Lists configured aliases with provider/model identity, active state, and the effective provider-derived `inputCapacity` when known. |
2755
2912
  | Model catalog | `listModels(query)` | Returns one validated bounded {§model-catalog-wire} page under {§model-catalog}; performs no provider request or selection. |
2756
2913
  | Client capabilities | `listClientDisplayCapabilities()` | Composes sorted scheme declarations ({§manifest-client-display}) followed by sorted MIME declarations ({§mimetype-client-display}) into the validated shared wire ({§client-display-capabilities}). The internal `exec` operation handler is excluded; its addressable runtime-tag scheme faces remain included. |
2757
- | §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings?, constraints? })` | Validates `settings` through {§operator-config-workspace-settings}, creates the world and its client envelope, applies constraints, and emits global `workspace/created`. Creation and attachment are passive: neither starts derivation nor activates worker Functionality. `projectRoot` is established here or the workspace remains headless. |
2914
+ | §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings? })` | Validates `settings` through {§operator-config-workspace-settings}, creates the world and its client envelope, and emits global `workspace/created`. Creation and attachment are passive: neither starts derivation nor activates worker Functionality. `projectRoot` is established here or the workspace remains headless. |
2758
2915
  | §methods-workspace-attach Workspace lifecycle | `attachWorkspace({ workspaceId, workerId?, workerName? })` | Validates ownership and returns a client envelope for an existing world. It does not retain caller or transport binding state in core. |
2759
2916
  | §methods-model-worker Workspace lifecycle | `ensureModelWorker(workspaceId)` | Returns the workspace's stable default model worker, creating it on first use. A durable default-conversation role identifies it independently of worker name and root creation order. Repeated and concurrent calls return the same root; fresh conversations and forks do not replace it. |
2760
2917
  | §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name? })` | Creates a distinct model-origin root worker with empty private history: a fresh conversation over the same world, not a fork or the stable default. |
2761
2918
  | Workspace lifecycle | `forkWorker({ workspaceId, workerId, name? })` | Creates a child worker that branches the source worker's history while sharing workspace state. |
2762
2919
  | §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
2763
- | Workspace metadata | `constrain(...)`, `unconstrain(...)`, `listConstraints(...)`, `listMembers(...)` | Owns the membership overlay and returns its resolved effects; clients do not reimplement constraint semantics. |
2764
2920
  | §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?)` | Returns nonempty loop-seed prompts from the workspace's model-origin root conversations, newest-first. The positive limit defaults to 100; spawned and forked child prompts are excluded. |
2765
2921
  | Workspace metadata | `listWorkspaces()`, `workspaceDerivationStatus(...)` | Reads current workspace identity and derivation progress. |
2766
2922
  | §methods-worker-read Worker topology | `readWorker({ workspaceId, identity })` | Ownership-bounds an exact id-or-name lookup and returns one durable Worker projection or `null` under {§application-worker-observation}. Supplying both identities or neither is invalid. |
@@ -2777,7 +2933,7 @@ already durable on the loop remains authoritative:
2777
2933
  |-----------------------|------------------------------------------------------|--------------------------------|--------------------------------------|
2778
2934
  | Provider/model | The resolved request selection must still agree. | Fold. | 409 provider conflict. |
2779
2935
  | `maxTurns` | Keep the durable ceiling. | Fold. | 409 turn-ceiling conflict. |
2780
- | Partial `flags` | Keep every effective durable flag. | Fold. | 409 flag conflict. |
2936
+ | Partial `policy` | Keep the complete durable loop policy. | Fold. | 409 policy conflict. |
2781
2937
 
2782
2938
  The conflict names both selections and directs the caller to cancel or conclude
2783
2939
  the loop before changing configuration. A newly enqueued loop instead persists
@@ -2813,17 +2969,43 @@ creation. A client therefore cannot forge or resume an internal worker, insert
2813
2969
  a non-mintable spelling, or make the client registry diverge from model worker
2814
2970
  control.
2815
2971
 
2972
+ §capability-admission **One admission path owns external authority.** Core
2973
+ derives one or more `CapabilityDescriptor` demands from each routed statement,
2974
+ then evaluates the service, workspace, immutable worker-bound, mutable worker,
2975
+ and loop policy layers in that order. Every demand of a composed operation must
2976
+ survive before execution or proposal creation. A denial is an exact terse 403
2977
+ identifying the denied descriptor and owning policy scope; it never guesses the
2978
+ model's intent or recommends an alternate operation. COPY demands observation
2979
+ of its source and mutation of its destination; MOVE additionally demands
2980
+ mutation of its source; resource-backed EXEC demands its runtime plus source
2981
+ observation. Unknown schemes, runtimes,
2982
+ and tools continue to their ordinary resolver so capability policy cannot turn
2983
+ absence into a misleading restriction. The same resolver shapes generated
2984
+ resource examples, worker tool documents, and Turn0 surveys. PLAN, OPEN, FOLD,
2985
+ log KILL, and targetless SEND are log/program control rather than routed
2986
+ external demands and therefore remain outside capability selectors.
2987
+
2816
2988
  §worker-settings **The worker carries its own behavioral rules.** The
2817
2989
  workspace is the world — how things are; each worker is an actor inside it,
2818
2990
  carrying the rules its loops obey. Those rules live in one JSON bag
2819
2991
  (`workers.settings`), declared by the client at worker creation and mutable
2820
- between loops through `readWorkerSettings`/`setWorkerSettings`; the bag is
2821
- validated at the client-input boundary against a closed known-key set, and
2822
- unknown keys never persist. A fork begins with the default empty bag — no
2823
- inherited rules, no live link. Readers are permissive: malformed persisted
2824
- JSON yields the default rules, never a read failure. There is no servicewide
2825
- or workspace ceiling on a worker's own rules; each client decides for its own
2826
- workers.
2992
+ between loops through `readWorkerCapabilities`/`setWorkerCapabilities`; the
2993
+ public operation is specifically capability-shaped rather than exposing the
2994
+ internal persistence bag. Input is validated at the client boundary, and
2995
+ unknown keys never persist. A fork begins with a default empty mutable bag, but
2996
+ its immutable `capability_bound` captures the delegating actor's effective
2997
+ authority under {§worker-delegation-inherits-policy}. Service and workspace
2998
+ policies remain live ceilings; worker and loop policies may narrow but never
2999
+ widen them. Malformed persisted settings or bounds fail at their owning reader
3000
+ with the worker coordinate and cause rather than silently granting defaults.
3001
+
3002
+ §worker-capability-inspection **Client inspection uses the admission
3003
+ resolver.** The Worker capability actions return the contracts-owned
3004
+ `CapabilityProjection` {§capability-policy-projection}: service, workspace, immutable Worker bound, mutable
3005
+ Worker policy, and their normalized effective intersection. The projection is
3006
+ computed by the same resolver used by dispatch and packet shaping. Changing
3007
+ the mutable layer returns a fresh complete projection, so a client cannot
3008
+ mistake a requested widening for effective authority.
2827
3009
 
2828
3010
  §question-tool **The native request-user-input tool.** Core registers one
2829
3011
  in-process `question` runtime at boot. Its body is the MCP2 2026-07-28
@@ -2836,17 +3018,17 @@ client-interaction lifecycle — durable pause, reconnect discovery,
2836
3018
  cancellation, and the answer-as-resolution all come from
2837
3019
  {§client-interactions}; there is no loopback MCP and no proposal masquerade.
2838
3020
  Effect `read`: the tool observes the human's answer and is never
2839
- proposal-gated. Admission is per-worker under {§worker-settings}: the tool
2840
- exists for a worker only when that worker's `requestUserInput` rule is set.
2841
-
2842
- §worker-tool-admission **Per-worker tool admission.** A runtime may be
2843
- admitted per worker through the reserved tool tree's visibility rule: the
2844
- find/read faces of the worker scheme drop a tool doc for an asking worker
2845
- whose own rules don't admit it, before matching and rendering, so counts,
2846
- weights, and the catalog text all agree — the tool does not exist for that
2847
- worker's FIND. Dispatch enforces the same boundary with an explicit
2848
- not-available outcome. Admission reads the worker's behavioral rules
2849
- ({§worker-settings}) at the operation boundary, never at registration.
3021
+ proposal-gated. Its runtime declares the `interaction` trait, which the shared
3022
+ resolver projects as access class `interact`; any capability-policy layer may
3023
+ therefore admit or deny it without a question-specific switch.
3024
+
3025
+ §worker-tool-admission **Tool visibility and execution share admission.** The
3026
+ reserved tool tree's FIND/READ faces drop a runtime or tool document whenever
3027
+ the effective worker-level capability layers deny its descriptor, before
3028
+ matching and rendering, so counts, weights, and catalog text agree. Turn0
3029
+ applies its loop layer to the same catalog projection. Dispatch evaluates that
3030
+ same descriptor and policy cascade at the operation boundary, never at
3031
+ registration; there is no separate per-tool availability system.
2850
3032
 
2851
3033
  §model-catalog **Model discovery is a bounded local projection, not provider
2852
3034
  activity.** Core composes the release-pinned Models.dev snapshot with
@@ -2955,7 +3137,7 @@ active lifecycle behind. LOOK text anchors resolve through the same
2955
3137
 
2956
3138
  | Event | Payload | When fired |
2957
3139
  |--------------------------------------------------------------|---------|------------|
2958
- | §notifications-log-entry-notify `log/entry` | `{ entry: LogEntry }` | A `log_entries` row is committed. |
3140
+ | §notifications-log-entry-notify `log/entry` | `{ entry: LogEntry }` | A non-proposed `log_entries` row is committed, or a proposed row reaches terminal settlement under {§proposal-proposed-hidden}. Delivery completes before a later event may terminate the owning Loop. |
2959
3141
  | §notifications-loop-terminated `loop/terminated` | `{ workerId, loopId, result, hitMaxTurns, turnIds, usage: { accounting, curationWeight, curationBudget, contextTokens, contextCapacity, 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}; the two curation facts and two physical-context facts follow {§tokenomics-client-gauge}; `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. |
2960
3142
  | §notifications-loop-packet `loop/packet` | `{ workerId, loopId, packetCount }` | One provider packet becomes durable. `packetCount` is the exact count of packet-bearing turns in that Loop; packetless producer turns and physical provider retries never contribute. |
2961
3143
  | §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}. |
@@ -2964,8 +3146,8 @@ active lifecycle behind. LOOK text anchors resolve through the same
2964
3146
  | §notifications-workspace-branch-batch `workspace/branch-batch` | Branch-batch lifecycle payload | A branch batch enters queued, running, completed, failed, or recovery-required state. |
2965
3147
  | §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. |
2966
3148
  | §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. |
2967
- | §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. |
2968
- | §notifications-reasoning-event `reasoning/event` | `{ workerId, loopId, turnId, modelCallId, phase, delta? }` | A main emission call exposes readable reasoning. A nonempty stream is balanced start/content/end; only content carries a nonempty exact delta. It is transient presentation evidence, never a log row, Notice, packet field, or BARE/child channel. The settled provider response remains the durable authority. |
3149
+ | §notifications-notice-event `notice/event` | `{ workerId, loopId, notice: Notice }` | A transient observation or progress notice occurs. `workerId` owns loop activity; only workspace derivation progress uses `null` with `loopId=0`. It cannot alter durable history, scheduling, recovery, or model-visible failure truth. |
3150
+ | §notifications-reasoning-event `reasoning/event` | `{ workerId, loopId, turnId, modelCallId, requestSequence, phase, delta? }` | A main emission call exposes readable reasoning. Each physical request that emits reasoning owns a distinct positive `requestSequence` and balanced start/content/end stream; opening a retry closes the preceding stream before any retry delta. Only content carries a nonempty exact delta. It is transient presentation evidence, never a log row, Notice, packet field, or BARE/child channel. The settled provider response remains the durable authority. |
2969
3151
 
2970
3152
  §notifications-stream-event-failure-isolation The plugin-facing
2971
3153
  `NotifyCaps.streamEvent()` remains a synchronous advisory call while core
@@ -3042,11 +3224,12 @@ Conditional absence never reorders the surviving default sections.
3042
3224
  | 6 | user | `log` | Append-mostly model-visible history. |
3043
3225
  | 7 | user | `child-streams` | Per-turn status; empty content is omitted. |
3044
3226
  | 8 | user | `child-workers` | Per-turn status; empty content is omitted. |
3045
- | 9 | user | `errors` | Per-turn failure pointers; empty content is omitted. |
3046
- | 10 | user | `notices` | Per-turn observations; empty content is omitted. |
3047
- | 11 | user | `git` | Per-turn workspace status; empty content is omitted. |
3048
- | 12 | user | `budget` | `Context Token Budget`; omitted when capacity is unknown. |
3049
- | 13 | user | `prompt` | Current prompt-entry pointers. |
3227
+ | 9 | user | `parent-worker` | The worker's parent by name; omitted for a root worker. |
3228
+ | 10 | user | `errors` | Per-turn failure pointers; empty content is omitted. |
3229
+ | 11 | user | `notices` | Per-turn observations; empty content is omitted. |
3230
+ | 12 | user | `git` | Per-turn workspace status; empty content is omitted. |
3231
+ | 13 | user | `budget` | `Context Token Budget`; omitted when capacity is unknown. |
3232
+ | 14 | user | `prompt` | Current prompt-entry pointers. |
3050
3233
 
3051
3234
  The order favors prefix-cache locality where semantics permit: the definition
3052
3235
  and privileged policy lead the resource directory, while the append-mostly
@@ -3102,9 +3285,10 @@ time of measurement.
3102
3285
  - **Derivation is exhaustive and demand-led.** Explicit searchable-resource changes may start one coalesced warm. Passive creation and attachment do not. The first model turn starts or joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or 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}
3103
3286
  - §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.
3104
3287
  - §tokenomics-agnostic-ruler **One model-agnostic curation ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. `contentWeight = ceil(chars/2)` therefore gives one content one stable number without per-model workspace state or recount passes. It controls curation only; every provider call independently measures the complete request as well as it can.
3105
- - §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Token Budget` section contains exactly two fields on separate lines: `tokensActiveTotal: N (P%)` and `tokensActiveMax: M`. It never presents their difference as free response tokens. The protocol definition directly requires FOLD, KILL, or trimming of irrelevant log items to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe OPEN cost and FOLD savings. Packet-level composition, rankings, and physical token speculation are absent.
3288
+ - §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Token Budget` section begins with exactly two fields on separate lines: `tokensActiveTotal: N (P%)` and `tokensActiveMax: M`. It never presents their difference as free response tokens. The protocol definition directly requires FOLD, KILL, or trimming of irrelevant log items to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe OPEN cost and FOLD savings. Generic packet composition and physical-token speculation are absent.
3289
+ - §tokenomics-pressure-inventory **Pressure identifies its reclaimable concentration.** When the ordinary two-field packet measurement reaches 80% of `tokensActiveMax`, the budget section may append `YOU MUST FOLD, KILL, or trim superseded, stale, or irrelevant log content.` followed by `Largest Log Items`: at most five currently OPEN, addressed log bodies, ordered by `tokensActive` descending and then `log:///` path. Each item repeats only that row's `tokensBody` and `tokensActive`. Folded and bodyless rows cannot enter the list because FOLD would reclaim no body from them. The largest prefix that fits may be shown; this conditional block never pushes an otherwise admissible packet over its maximum. Its own weight participates in the final fixed-point `tokensActiveTotal`.
3106
3290
  - §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as stable content identity. `weight` is stored beside that content and is never keyed or recomputed by model.
3107
- - §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` sums every USD-expressible request and is `null` only when no request is expressible; a response-less failure or an uncataloged model is skipped, never allowed to erase the expressible evidence. The derived aggregate usage sums every reported quantity the same way. 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.
3291
+ - §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity beneath the normalized {§inference-ledger} and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` and `embedding_calls` own domain response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, embeddings, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` sums every USD-expressible request and is `null` only when no request is expressible; a response-less failure or an uncataloged model is skipped, never allowed to erase the expressible evidence. Each derived aggregate usage field independently sums its reported quantity, so heterogeneous detail coverage remains partial rather than becoming fictitiously complete. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot FOLD, so they never alter the model-facing Budget ledger.
3108
3292
  - §tokenomics-negative-pressure **Negative curation pressure is honest but never submitted.** The provisional readout may report `tokensActiveTotal` and its percentage above `tokensActiveMax`. Crossing the maximum diverts that would-be model turn into {§overflow-turn}; no over-ceiling packet reaches `provider.generate`. Automatic recovery does not create a strike or consume a model-turn allowance.
3109
3293
 
3110
3294
  ### §membership Workspace identity, membership, disk co-location
@@ -3114,16 +3298,13 @@ not participate in this disk loop.
3114
3298
 
3115
3299
  ```mermaid
3116
3300
  flowchart LR
3117
- git["Git tracked +<br/>untracked-not-ignored"] --> resolve["Resolve workspace membership"]
3118
- pick["pick"] --> resolve
3119
- hide["hide"] -->|subtract| resolve
3301
+ git["Git tracked"] --> resolve["Resolve workspace membership"]
3302
+ include["include"] --> resolve
3303
+ exclude["exclude"] -->|subtract| resolve
3120
3304
  resolve --> materialize["Pre-turn materialize<br/>disk → file snapshot"]
3121
3305
  materialize --> read["READ snapshot"]
3122
3306
  materialize --> edit["EDIT against snapshot"]
3123
- edit --> gate{"view?"}
3124
- view["view"] -->|marks member read-only| gate
3125
- gate -->|yes| refused["403; no proposal"]
3126
- gate -->|no| proposal["Proposal"]
3307
+ edit --> proposal["Proposal"]
3127
3308
  proposal -->|"client accepts or loop auto"| cas["synced_sig compare-and-swap"]
3128
3309
  cas -->|"file snapshot → disk"| project["Project file"]
3129
3310
  project --> materialize
@@ -3132,11 +3313,11 @@ flowchart LR
3132
3313
  | Concern | Owner and representation |
3133
3314
  | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
3134
3315
  | Workspace identity | `workspaces.project_root`; null is headless. There is no separate project entity. |
3135
- | File visibility | Workspace-tier resolved membership: `(repository files ∪ pick) − hide`, with `view` read-only. Every worker sees the same result. |
3316
+ | File visibility | Workspace-tier resolved membership: `(tracked files ∪ include) − exclude` ({§membership-baseline}). Every worker sees the same result. |
3136
3317
  | File reads | READ returns the materialized file snapshot stored in the entry body channel; it does not read disk directly. |
3137
3318
  | File writes | EDIT proposes against that snapshot. Only accepted resolution with the captured `synced_sig` writes the project file. |
3138
3319
  | Internal entries | Workspace or worker entries are canonical store state. Writing one never implies a project-file write. |
3139
- | Authority | Service flags set the membership ceiling; workspace constraints narrow it; client or loop auto resolves proposals. `origin` is attribution. |
3320
+ | Authority | Service flags set the membership ceiling; the `members` family's definitions include and exclude within it; client or loop auto resolves proposals. `origin` is attribution. |
3140
3321
 
3141
3322
  §web-search-retrieval **Web discovery is an ordinary MCP concern; retrieval is a first-class composition.** PLURNK owns no search runtime: a search-capable MCP server (e.g. Brave Search) participates through the ordinary MCP contract — admission, read-effect classification, tool documentation, and packet projection are identical to every other MCP tool ({§mcp-tool-presentation}). An executor that wants to materialize discovered pages uses the generic `content: null` `entry()` request ({§exec-entry-sink}): the guarded `WebFetcher` sink fetches candidates in parallel, off the write-serialization chain, and materializes successful bodies as ordinary HTTP entries. Every candidate whose `entry()` call rejects, regardless of failure reason, is mechanically omitted from the model-facing result directory; survivors retain upstream order. Without an entry sink the executor cannot test materialization and omits the verdict.
3142
3323
 
@@ -3155,31 +3336,58 @@ and never re-fetch a match.
3155
3336
 
3156
3337
  **Git is the substrate and the repository is the boundary:**
3157
3338
 
3339
+ - §membership-baseline **The baseline contract — chiseled (#400).** To a workspace a
3340
+ project file is exactly one of three things: **invisible**, **added**, or **tracked
3341
+ by git**. There is no fourth category. Membership — what the model can READ and
3342
+ FIND, what is materialized into the store, what a packet can ship to a provider — is
3343
+ the allowlist `(tracked ∪ include) − exclude` and nothing else. No file is a member because
3344
+ it exists on disk, because git does not ignore it, or because a model would find it
3345
+ convenient: ambient admission of untracked files is prohibited, so a workspace rooted
3346
+ in a home directory or a monorepo exposes exactly what was committed or added (the
3347
+ non-member rule, {§fs-write-nonmember}: no read, no leak, no overwrite). Every
3348
+ exception is a named clause in the register ({§membership-model-universe}), admits
3349
+ files by an exact creation record with recorded provenance, and never by `git add`.
3350
+ Changing this clause, the register, or the composition is an operator ruling recorded
3351
+ on the issue that lands it — never an implementation convenience, never a side effect
3352
+ of making a file visible to solve the problem at hand. The 2026-07-12 – 2026-08-27
3353
+ "untracked-but-not-ignored" ambient admission is retired.
3354
+ - §membership-model-universe **The exception register — files in the model's universe.**
3355
+ Admitted by exact creation records (`source: "create"`, origin `constraint`), never
3356
+ staged: (1) a file an accepted EDIT creates; (2) a COPY/MOVE destination
3357
+ ({§membership-create-parents}). Admitted by a published standard as projected
3358
+ instruction documents — never as members: (3) the project's `AGENTS.md` and nested
3359
+ `AGENTS.md` files ({§turn0-agents-stunt}, #346), read from disk regardless of git status
3360
+ and materialized as `worker://~/_plurnk/agents.md` and
3361
+ `worker://~/_plurnk/instructions/<subtree>/AGENTS.md`; the file itself is a member
3362
+ only when tracked or added, and the standard never overrides the operator's
3363
+ exclusions — an `AGENTS.md` the repository ignores or an exclusion matches
3364
+ is not projected. (4) A definition the model proposes through the `members`
3365
+ family ({§members-functionality}), admitted only under the operator's ceiling
3366
+ `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` (shipped `none`), projected with source
3367
+ `model`, and never admitted past the repository's ignore rules or an exclusion.
3368
+ Nothing else.
3158
3369
  - §membership-git-membership The workspace owns the Git repository containing
3159
3370
  `project_root`. Its tracked files (`git ls-files` semantics) are members with
3160
3371
  no explicit overlay; when the root is a package inside a monorepo, the
3161
3372
  repository's other packages are members at root-relative paths. An unrelated
3162
3373
  or nested independent repository is not discovered or managed by this
3163
- workspace. When Git is absent there is no filesystem walk; `pick` is then the
3164
- sole source.
3374
+ workspace. When Git is absent there is no filesystem walk; member definitions are
3375
+ then the sole source.
3165
3376
  - §git-native-default **Core Git reads use native Git.** Membership and status
3166
3377
  execute the installed Git binary. An absent or failed binary yields no
3167
3378
  automatic Git membership or status; core has no alternate implementation or
3168
- fallback. An independently installed `isogit` executor remains an explicit,
3169
- model-invoked subset for shellless deployments, not an ambient Git backend.
3379
+ fallback.
3170
3380
  - §membership-git-hermetic Native Git runs with ambient `GIT_*` and
3171
3381
  global/system config scrubbed, so repository identity follows `project_root`,
3172
3382
  never the daemon's launch environment.
3173
3383
  - §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** crosses the creation matrix in {§fs-write-surface}; proposal acceptance cannot bypass its scope, exclusion, or incorporation rules. Reaching past membership is `## EXEC0 [sh]`'s job, not the file scheme's.
3174
3384
  - §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.
3175
3385
 
3176
- **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.
3386
+ **The overlay — `include | exclude`.** `workspace_constraints` holds the `members` family's projected definitions and the engine's creation records ({§members-projection}). Resolved membership is `(project repository files ∪ include) − exclude`.
3177
3387
 
3178
- - §membership-auto-add **Auto-add** — the project repository's ambient membership is its tracked `ls-files` plus untracked-but-not-ignored files (`git ls-files --others --exclude-standard`), with `git` origin. An accepted creation selected for Git incorporation is explicitly staged; failure falls back to an exact generated pick, never an orphan ({§file-create-no-orphans}).
3179
- - §membership-overlay-pick **`pick`** — admit a file Git misses through a targeted constraint scan (files only), with `constraint` origin. `source: "explicit"` records operator/client policy; `source: "create"` is the exact durable record of an accepted creation. Only explicit picks override active Git ignore. In a Git-absent root, picks are the sole file-membership source.
3180
- - §membership-overlay-hide **`hide`** — exclude a tracked or picked file: resolution drops matches (`node:path.matchesGlob`) and reconciles so the entry set *equals* the member set. The lever to exclude a committed-but-sensitive tracked file; exclusions mask generated creation picks without deleting their provenance ({§fs-create-masked}).
3181
- - §membership-overlay-view **`view`** — keep a member readable but refuse `File.edit`, 403'd at the membership check before any diff. (Admitting an untracked file as `view` rides on `pick`'s scan.)
3182
- - §membership-resolved-effects **Resolved effect is a read, not a re-derivation.** `workspace.members` surfaces each candidate's resolved effect — `(ls-files ∪ pick) − hide` tagged `member` / `view`, plus the `hide`-excluded `hidden` set — so a client signs file visibility (member / read-only / ignored) without reimplementing the overlay glob-matching. The daemon owns git + the globs; the per-file effect is its to resolve, the client's to render.
3388
+ - §membership-auto-add **Auto-add** — the project repository's ambient membership is its tracked `ls-files`, with `git` origin; an untracked file is never an ambient member ({§membership-baseline}). An accepted creation is incorporated by an exact creation record, never by `git add` ({§membership-model-universe}); a record that cannot be written fails the creation transaction, never an orphan ({§file-create-no-orphans}).
3389
+ - §membership-overlay-include **`include`** — admit a file Git misses through a targeted pattern scan (files only), with `constraint` origin. `source: "members"` is a projected human definition, `source: "model"` a projected model definition, `source: "create"` the exact durable record of an accepted creation. Only `members` inclusions override active Git ignore. In a Git-absent root, inclusions are the sole file-membership source.
3390
+ - §membership-overlay-exclude **`exclude`** — a `!glob` definition removes a tracked or included file: resolution drops matches (`node:path.matchesGlob`) and reconciles so the entry set *equals* the member set. The lever to exclude a committed-but-oversized or sensitive tracked file; exclusions mask creation records without deleting their provenance ({§fs-create-masked}).
3183
3391
 
3184
3392
  **File ops act on the entry, not the disk; the two reconcile only at gates.** A `file:///` member is a row whose body channel holds its *materialized model-readable snapshot*. READ returns that channel; EDIT diffs against editable text snapshots — neither reaches the filesystem directly. Entry and disk reconcile at exactly two gates: the **pre-turn materialize** (disk → entry, below) and the **accept-time write-back** (entry → disk, {§proposal}). Between the gates the entry is the truth the model curates against, and `synced_sig` — the member's last-synced disk stat (`mtime:size`) — is the version token both gates compare on.
3185
3393
 
@@ -3194,7 +3402,21 @@ identity, and terminal disposition without exposing raw bytes or a base64 lane.
3194
3402
  | Binary with readable projection | Derived Unicode as `text/markdown` | READ uses the projection; source-aware EDIT remains 415. |
3195
3403
  | Binary without projection/over cap | Empty marker under the source binary mimetype | READ and EDIT return 415; private metadata distinguishes unavailable from limit. |
3196
3404
 
3197
- §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row, 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 representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
3405
+ §membership-materialization-limit **A pathological member degrades, never the
3406
+ workspace.** `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` is a required positive
3407
+ byte ceiling over one disk source before Core reads it into the canonical file
3408
+ snapshot. Its valid range is `1..104857600`, bounded by the channel storage
3409
+ contract, and it ships at that 100 MiB maximum. An oversized path remains a real member
3410
+ with an empty body channel carrying a durable 413 producer result; no diagnostic
3411
+ sentinel impersonates file content. READ therefore names the path, observed bytes,
3412
+ ceiling, and recovery through the ordinary result contract, while EDIT returns the
3413
+ same 413 instead of diffing against a fictitious empty baseline. Core records the
3414
+ materialization disposition and ceiling privately, so an unchanged disk member is
3415
+ reconsidered when the operator changes the policy and otherwise remains a stat-only
3416
+ no-op. The file write gate independently stats the source against the same ceiling,
3417
+ so safety does not depend on a background warm winning a client-operation race.
3418
+
3419
+ §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row, 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 launched worker settles before the maintenance pass reports success or failure, so one failed artifact cannot orphan sibling inference or its accounting. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
3198
3420
 
3199
3421
  The artifact also retains a positive `{§mimetype-parse-issues}` count and the
3200
3422
  full normalized `{§mimetype-summary}` when the exact parsed channel reported
@@ -3215,13 +3437,13 @@ every non-vector attachment with its disposition and reason. Successful
3215
3437
  optional projection degradations continue indexing and surface their framework
3216
3438
  Notice once per identical observation in a maintenance pass.
3217
3439
 
3218
- §semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json` channels - and any log result exposing the same exact readable text - attach one content-addressed derivation artifact. Graph, FTS, and chunk vectors exist once; addresses join through the artifact hash. One pass-wide semantic plan binds the selected chunk counter to this identity: the embedder's own counter is covered by model-space identity, while a separately resolved fallback counter contributes its `tokenizerId` and exactness. Model, vocabulary, vector-wire encoding ({§mimetype-embedding-wire}), or configuration changes therefore produce a different identity, so incompatible vector spaces, encodings, or chunk boundaries never share.
3440
+ §semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json` channels - and any log result exposing the same exact readable text - attach one content-addressed derivation artifact. Graph, FTS, and chunk vectors exist once; addresses join through the artifact hash. One pass-wide semantic plan binds the selected chunk counter and deterministic tiling revision to this identity: the embedder's own counter is covered by model-space identity, while a separately resolved fallback counter contributes its `tokenizerId` and exactness. Model, vocabulary, tiling behavior, vector-wire encoding ({§mimetype-embedding-wire}), or configuration changes therefore produce a different identity, so incompatible vector spaces, encodings, or chunk boundaries never share.
3219
3441
 
3220
3442
  Lossless chunk admission requires either the embedder's own counter or an exact fallback tokenizer. An empirical estimate never proves that content fits the declared token window. When pending readable content would require vectors and only an estimate is available, maintenance surfaces its degradation Notice and fails before embedding or attaching a derivation; no/disabled embedding and the established empty, binary, excluded, and maximum-size dispositions remain non-vector outcomes.
3221
3443
 
3222
- §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 addressed channel representation READ exposes and the embedder receives. Exhaustive embedding therefore remains the normal posture. When a nonzero ceiling rejects an oversized representation, its channel 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 channels. Client notices report compact aggregate progress; the digest records every non-vector address, terminal disposition, and reason for forensic inspection.
3444
+ §semantic-max-embed-size **Embedding has a bounded size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is the maximum UTF-8 byte size eligible for vectors; the shipped default is 262144 and `0` is the explicit unlimited override. The measured value is the exact addressed channel representation READ exposes and the embedder receives. When the ceiling rejects an oversized representation, its channel 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 channels. Client notices report compact aggregate progress; the digest records every non-vector address, terminal disposition, and reason for forensic inspection.
3223
3445
 
3224
- §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}.
3446
+ §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 and materialization policy 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} and {§membership-materialization-limit}.
3225
3447
 
3226
3448
  §membership-emi-divergence-signal **EMI divergence evidence.** The detector that gates the work *is* the one that records this — one mechanism, not a second full read. When change detection finds a member moved out-of-band, the runtime actor records an `EDIT`-shaped row naming the file with `source="file"`; it does not broadcast that workspace change into unrelated workers' logs ({§env-delta-filesystem-narration}). 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. The current file remains ordinarily addressable. A stale anchored edit rejects under {§line-anchors}; a disk race after proposal rejects under {§membership-edit-write-cas}.
3227
3449
 
@@ -3231,13 +3453,13 @@ The version travels *with the proposal*, never re-read from the entry at accept:
3231
3453
 
3232
3454
  The CAS is the **hard backstop**, at the moment of writing, on every accept path. It composes with the model-facing {§line-anchors}: an anchor rejects a target whose relevant neighborhood changed before dispatch, while the CAS refuses to write against a snapshot disk left after proposal. An unanchored edit deliberately claims no pre-dispatch stale-view guarantee.
3233
3455
 
3234
- §membership-git-flags **Permission flags.** Service-wide Git admission comes from {§operator-config-git-ceiling}. `PLURNK_SERVICE_GIT_AUTO=1` (default) includes the repository containing `project_root`; `=0` disables automatic Git membership, leaving `pick` as the only membership source. `ALLOWED` gates `AUTO`.
3456
+ §membership-git-flags **Permission flags.** Service-wide Git admission comes from {§operator-config-git-ceiling}. `PLURNK_SERVICE_GIT_AUTO=1` (default) includes the repository containing `project_root`; `=0` disables automatic Git membership, leaving member definitions as the only membership source. `ALLOWED` gates `AUTO`.
3235
3457
 
3236
3458
  **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.
3237
3459
 
3238
- **Schema.** The version-1 baseline stores logical model calls beneath turns,
3239
- emission admission as their specialization, and cardinal physical requests
3240
- beneath each call. Its constraints distinguish pending calls, response
3460
+ **Schema.** The version-1 baseline stores the normalized {§inference-ledger},
3461
+ its generation or embedding specialization, emission admission, and cardinal
3462
+ physical requests. Its constraints distinguish pending calls, response
3241
3463
  evidence, and response-less errors while monetary classification remains
3242
3464
  explicit.
3243
3465
 
@@ -3271,11 +3493,15 @@ provider I/O.** After packet assembly, Core compares render weight
3271
3493
  ({§tokenomics}) with the provider-derived curation ceiling. An admitted packet
3272
3494
  ships untouched. An over-ceiling candidate is never stored as a model request
3273
3495
  and never reaches `provider.generate`; its already-created database turn instead
3274
- becomes a packetless `_plurnk` turn. Packetless initialization and recovery turns
3496
+ becomes a packetless `_plurnk` turn. Engine-side inference already booked to that
3497
+ turn (embedding work from semantic attachment) never blocks the transition; only
3498
+ a model emission or BARE call does, because those are model history and the
3499
+ producer cannot change beneath them (run67, 2026-08-29: a 90k-window model died
3500
+ at its first overflow because four embedding calls were counted as history). Packetless initialization and recovery turns
3275
3501
  remain ordinary turn chronology but do not consume `maxTurns`, model-call,
3276
3502
  emission-attempt, usage, or cost accounting.
3277
3503
 
3278
- - §overflow-turn-script **Recovery is one ordinary admitted `_plurnk` program.** Its canonical {§plan-value} has one `medium`, `in_progress` entry whose content is `Automatically FOLD log bodies newly active at token-budget overflow.`, followed by every causal whole-body FOLD and terminal `SEND0 [102]` with body `Next: YOU MUST ONLY FOLD, KILL, or trim ALL superseded, stale, or irrelevant log content in bulk in the next turn.` The final sentence requires the successor's substantive operations to be one dedicated, comprehensive bulk-curation program; mandatory PLAN and SEND framing still applies. Its exact `turnOps` is born FOLDED; successful FOLD rows follow {§fold-open-meta-operations} and therefore remain durable but packet-suppressed. Every recovery row carries `_plurnk` and `overflow`; no model call, synthetic receipt, or parallel explanation exists.
3504
+ - §overflow-turn-script **Recovery is one ordinary admitted `_plurnk` program.** Its canonical {§plan-value} has one `medium`, `in_progress` entry whose content is `Automatically FOLD log bodies newly active at token-budget overflow.`, followed by every causal whole-body FOLD and terminal `SEND0 [102]` with body `Next: YOU MUST ONLY FOLD, KILL, or trim ALL superseded, stale, or irrelevant log content in bulk.` The final sentence requires the successor's substantive operations to be one dedicated, comprehensive bulk-curation program. Core authors this internal program with canonical PLAN and SEND framing. Its exact `turnOps` is born FOLDED; successful FOLD rows follow {§fold-open-meta-operations} and therefore remain durable but packet-suppressed. Every recovery row carries `_plurnk` and `overflow`; no model call, synthetic receipt, or parallel explanation exists.
3279
3505
  - §overflow-turn-curation **The preceding turn owns the pressure it introduced.** Core deterministically selects every body already created in the packetless candidate turn, every body created by the immediately preceding completed turn in that worker's chronology, and every older body whose visibility that preceding turn's successful OPEN increased. Every selected body is FOLDed whole (`<1,-1>`) through ordinary dispatch. Already-wholly-folded and bodyless rows require no operation. Core performs no relevance judgment, exempts no operation or resource kind, reconstructs no interval delta, re-runs no authored selector, and chooses no unrelated older history.
3280
3506
  - §overflow-turn-hard-413 **Recovery fails hard when the causal fold cannot fit.** After the ordinary FOLDs land, Core rebuilds and remeasures once. If the plan changes no visibility or the rebuilt request still exceeds the ceiling, the loop terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem; Core neither submits excess bytes nor chooses unrelated older history. Separately, every `provider.generate` assesses physical capacity under {§provider-surface-capacity}. Core may retry a provider capacity rejection only after withholding automatic prompt-body projection when that changes the request. If it cannot produce changed bytes or the changed request is still rejected, the request-only model turn and provider-owned Problem terminalize at **413 Content Too Large**.
3281
3507
 
@@ -3353,7 +3579,7 @@ ordinary operation evidence still reaches that child's direct parent.
3353
3579
  | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3354
3580
  | `worker_id` | The worker whose self-contained log owns the materialized row. |
3355
3581
  | `origin` | The actor tier that wrote the row; a materialized delta is `_plurnk`. |
3356
- | `source` | The immediate causal identity in this log. A lineage or commons observation uses the canonical `worker://<producer>` control identity; self-authored rows omit it. |
3582
+ | `source` | The immediate causal identity in this log: a lineage or commons observation uses canonical `worker://<producer>`, a terminal stream observation uses its causal `log:///<coord>/EXEC`, and a subsystem observation may use its stable token (for example `file`). Self-authored rows omit it. |
3357
3583
 
3358
3584
  §env-delta-no-coalescing **Activity is never coalesced.** Each admitted child
3359
3585
  operation and each commons mutation has one occurrence identity. Combining
@@ -3389,6 +3615,8 @@ flowchart LR
3389
3615
  body --> recall["READ log:///…<br/>recalls canonical body"]
3390
3616
  ```
3391
3617
 
3618
+ §edit-receipt-anchored-context **An applied EDIT's resulting context carries anchors.** The bounded resulting context each effect renders (`PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` around and inside the landed region) is rendered exactly as a READ renders — `@xxxxx L:text`, hashed with the resource's READ identity ({§line-anchors}) — so the next batch cites the landed lines by anchor without a READ; both requiems of 2026-08-29 asked for this. A scheme that supplies no identity keeps the line-numbered form.
3619
+
3392
3620
  §edit-result-receipt-projection **EDIT projects the scheme-owned batch
3393
3621
  receipt.** The scheme framework owns the exact aggregate shape
3394
3622
  ({§scheme-edit-batch-receipt}). Core validates it and projects the result
@@ -3401,7 +3629,7 @@ the aggregate remains dispatch coordination state.
3401
3629
  | -------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
3402
3630
  | 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. |
3403
3631
  | `unit`, `before`, `after` | `extent` | Whole-line batches use line counts. A batch containing any exact four-coordinate edit uses Unicode code-point counts. |
3404
- | `parseIssues` | `parseIssues` | Positive parser-recovery count for the complete landed revision; clean, unsupported, and unavailable evidence is omitted. |
3632
+ | `parseIssues.before`, `parseIssues.after` | `parseIssues` as `before→after` | Parser-recovery counts for complete source and landed revisions; omitted when both are clean or either is unavailable. |
3405
3633
  | `effect.requested`, `source`, `result` | `range` | The admitted marker and its normalized mapping from the common source snapshot into the landed body. |
3406
3634
  | `effect.removed`, `inserted` | `change` | Removed and inserted counts in the receipt unit. |
3407
3635
  | `effect.context` | Canonical row body | Numbered physical lines at each landed boundary, bounded symmetrically by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
@@ -3410,7 +3638,7 @@ the aggregate remains dispatch coordination state.
3410
3638
 
3411
3639
  §edit-result-receipt-truth **Receipts describe committed state.** Every row in
3412
3640
  one resource-channel EDIT batch carries the same landed revision, extent, and
3413
- optional positive `parseIssues` count for that complete revision.
3641
+ optional `parseIssues` transition for the complete source and landed revisions.
3414
3642
  When the proposed batch lands unchanged, each row also carries its own requested
3415
3643
  marker, source/result mapping, counts, and context. For configured count `C`,
3416
3644
  the context contains up to `C` surrounding lines and the first and last `C`
@@ -3467,7 +3695,7 @@ inspection is advisory and occurs against complete resulting text after
3467
3695
  successful application. A handler or parser failure emits a Notice, omits
3468
3696
  `parseIssues`, and never changes the mutation outcome.
3469
3697
 
3470
- ### §proposal-ownership Loop auto and client YOLO
3698
+ ### §proposal-ownership Loop disposition and client YOLO
3471
3699
 
3472
3700
  Side-effecting operations propose ({§exec}) and pause dispatch at 202 for an
3473
3701
  authority decision ({§engine-rails}, {§methods}). Automatic acceptance has two
@@ -3475,14 +3703,14 @@ distinct owners:
3475
3703
 
3476
3704
  | Mechanism | Authority path | Intended use |
3477
3705
  | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
3478
- | §proposal-ownership-loop-auto **Loop auto** | `runLoop({ flags: { auto: true } })` or client sugar sets `loops.flags.auto=true`; core's loop disposition resolves in process without a client. | Headless automation, benchmarks, CI, fixtures, and unattended use. |
3479
- | **Client-side YOLO** (`--yolo` / `PLURNK_YOLO`) | The daemon emits the ordinary `loop/proposal`; the client returns an accepted proposal through its standard resolution path (AG-UI resume). | Interactive automatic review. |
3706
+ | §proposal-ownership-loop-auto **Loop disposition** | `runLoop({ policy: { proposals: "accept" } })` persists a loop-owned disposition; core resolves proposals in process without a client. | Headless automation, benchmarks, CI, fixtures, and unattended use. |
3707
+ | **Client-side YOLO** (`--yolo` / `PLURNK_YOLO`) | A `proposals: "review"` loop emits the ordinary `loop/proposal`; the client returns an accepted proposal through its standard resolution path. | Interactive automatic review. |
3480
3708
 
3481
3709
  Core cannot distinguish client-side YOLO from a fast human acceptance and does
3482
3710
  not need to. Loop auto keeps authority inside the loop; client-side YOLO acts
3483
3711
  only after authority crosses the client boundary.
3484
3712
 
3485
- §proposal-ownership-notification **The notification carries disposition, not policy inputs.** `loop/proposal` carries the core-owned `ProposalDisposition` ({§notifications}, {§proposal-disposition}). A connected client presents only `owner="client"`; it never reimplements precedence from flags, operation, or attrs.
3713
+ §proposal-ownership-notification **The notification carries disposition, not policy inputs.** `loop/proposal` carries the core-owned `ProposalDisposition` ({§notifications}, {§proposal-disposition}). A connected client presents only `owner="client"`; it never reimplements policy from operation or attrs.
3486
3714
 
3487
3715
  ---
3488
3716
 
@@ -3492,8 +3720,9 @@ only after authority crosses the client boundary.
3492
3720
  when an emission is admitted, its response.** Core assembles and measures the
3493
3721
  request under {§packet-assembly}. An admitted response extends that same record
3494
3722
  before the turn closes; a failed provider call or exhausted invalid emission
3495
- leaves the request-only record, while rejected exchanges remain in
3496
- `model_calls` with their classification in `turn_attempts`.
3723
+ leaves the request-only record, while rejected exchanges remain in their
3724
+ `inference_calls`/`model_calls` evidence with classification in
3725
+ `turn_attempts`.
3497
3726
 
3498
3727
  | Turn state | `turns.packet` |
3499
3728
  | ----------------------------- | ----------------------------------------------- |
@@ -3520,9 +3749,10 @@ source independently from this optional model-exchange record; a request-only
3520
3749
  turn receives a note instead of a fabricated response.
3521
3750
 
3522
3751
  §digest-turn-artifact-identity **Digest packet artifacts project durable turns.**
3523
- After selectors are applied, digest retains every turn with exact `turnOps` or
3524
- a stored provider request, orders those turns by durable chronology, and names
3525
- them contiguously from `packet000`. The producer does not affect projection.
3752
+ After selectors are applied, digest retains every turn with exact `turnOps`, a
3753
+ valid stored provider request, or malformed stored packet evidence; orders those
3754
+ turns by durable chronology; and names them contiguously from `packet000`. The
3755
+ producer does not affect projection.
3526
3756
 
3527
3757
  | Artifact | Present when | Authority |
3528
3758
  |----------|--------------|-----------|
@@ -3530,6 +3760,8 @@ them contiguously from `packet000`. The producer does not affect projection.
3530
3760
  | `packetNNN.system.md`, `packetNNN.user.md` | The turn stored a provider request | Stored packet sections projected through `PacketWire` |
3531
3761
  | `packetNNN.assistantRaw.json` | The request has an admitted provider response | Stored opaque provider response |
3532
3762
  | `packetNNN.response.md`, attempt artifacts | The request received no admitted response | Stored request and attempt state |
3763
+ | `packetNNN.packet.raw.txt` | The stored packet fails typed validation | Exact stored packet text |
3764
+ | `packetNNN.packet.invalid.json` | The stored packet fails typed validation | Turn identity and complete validation error chain |
3533
3765
 
3534
3766
  A source-backed turn without provider participation therefore produces only
3535
3767
  `assistant.md`; a request-only turn produces no fabricated assistant. A
@@ -3633,7 +3865,9 @@ retain distinct contracts and lifetimes.
3633
3865
  - §log-row-self-explains **Every ≥400 pointer names a record that states its
3634
3866
  why.** A model-operation failure is the model's own operation result; its
3635
3867
  Problem Details `instance` is that row's `log:///` URI and packet wire renders
3636
- the exact `problem` object on its meta line whether folded or open. No
3868
+ the contracts-owned compact `{§problem-projection}` on its meta line whether
3869
+ folded or open. The enclosing row owns status, model-facing path, source, and target;
3870
+ an identical extension is not repeated inside the projection. No
3637
3871
  separate item is minted for operation failures. Actionless engine rails mint
3638
3872
  `op='error'` items because no authored operation row exists. Invalid provider
3639
3873
  emissions are outside this channel because they are not turns. A bare
@@ -3642,9 +3876,9 @@ retain distinct contracts and lifetimes.
3642
3876
  engine-internal faults crash and never mint model-facing rows.
3643
3877
  - **Asynchronous work does not weaken the contract.** A stream-producing operation returns its initial `102` after acquisition. At conclusion the subscription stores the exact universal terminal result; `stream/concluded` carries it unchanged; the next ambient terminal READ merges it with the stream payload and assigns the committed `log:///.../READ` Problem instance. Timeouts and service cancellations replace the complete terminal result with a new valid 504/499 Problem—they never mutate a status while retaining a contradictory Problem.
3644
3878
  - **Self-explaining rows.** A problem `title` names the stable class and `detail` states the occurrence-specific cause. Producer-known operands belong in factual extensions. `stage` appears only when neighboring stages imply different recovery; `recovery` states one generally valid next action; `retryable` is true only when the producer recommends automatically retrying the identical request. Unknown recovery or retryability is omitted rather than guessed. General workflow teaching stays in the packet rather than being duplicated into every failure. The runtime-neutral writing contract is owned by `@plurnk/plurnk-contracts`.
3645
- - **Exact Problems cross every boundary.** Scheme capabilities, proposal application, subscription conclusion, loop settlement, AG-UI, clients, digests, and benchmark records preserve the originating Problem object. An adapter may add the durable `instance`; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, a scheduler projection, or a legacy string. A failed boundary without a valid Problem is a contract violation and fails hard.
3879
+ - **Exact Problems cross durable and external boundaries.** Scheme capabilities, proposal application, subscription conclusion, loop settlement, AG-UI, clients, digests, and benchmark records preserve the originating Problem object. The model packet alone derives `{§problem-projection}` without mutating that object. An adapter may add the durable `instance`; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, a scheduler projection, or a legacy string. A failed boundary without a valid Problem is a contract violation and fails hard.
3646
3880
  - **Caught diagnostics are bounded.** Core-owned Problems may include a bounded preview of a caught runtime diagnostic when it states the occurrence-specific cause. `PLURNK_SERVICE_ERROR_DETAIL_LIMIT` owns that model-facing character bound; complete errors remain in daemon diagnostics. Input validation and stable contract failures do not spend this allowance on implementation text.
3647
- - §notice-drain-on-read **Notices** - the few observations that are not log rows render one terse line under their distinct `## Notices` section, never a JSON dump. Packet rendering normalizes whitespace, bounds the producer message with the shared preview limits, and appends any typed position. The notice buffer drains on read; each appears on exactly one packet.
3881
+ - §notice-drain-on-read **Notices** - the few observations that are not log rows render one terse line under their distinct `## Notices` section, never a JSON dump. Packet rendering normalizes whitespace, bounds the producer message with the shared preview limits, and appends any typed position. The notice buffer drains on read; event Notices appear on at most one packet. Stateful derivation progress and provider availability coalesce in the buffer, so clients observe every checkpoint live while a later model packet receives only the current state under ordinary level filtering.
3648
3882
  - §rail-accounting-private **Rail accounting is private.** Visibility is owned by {§engine-rails}: the model sees concrete failures from admitted turns, never rejected emissions, attempt counts, the strike streak, or cycle detection. Surfacing internal state creates a gamification surface where the model optimizes for engine metrics instead of the task.
3649
3883
 
3650
3884
  **The error rows (one channel) + the only non-log notices:**
@@ -3666,7 +3900,7 @@ retain distinct contracts and lifetimes.
3666
3900
 
3667
3901
  §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.
3668
3902
 
3669
- §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.
3903
+ §notice-event-notify **Client surface.** Engine Notices broadcast live via the `notice/event` notification — `{ workerId, loopId, notice: { source, kind, level, message?, position?, …kind-specific } }` per the grammar's `Notice` schema — the moment they land. A loop Notice names its owning Worker; workspace derivation progress alone carries `workerId=null, loopId=0`. 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.
3670
3904
 
3671
3905
  §digest-programmatic-surface **The digest is an importable forensic surface.**
3672
3906
 
@@ -3675,10 +3909,10 @@ retain distinct contracts and lifetimes.
3675
3909
  | Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its package-owned SqlRite statements; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
3676
3910
  | `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
3677
3911
  | `digestDir` | Selects the output directory. `run` removes and recreates it so stale packet artifacts cannot survive; concurrent callers use distinct directories. |
3678
- | `workerId` | Narrows workers and every dependent loop, turn, logical model call, emission attempt, physical request, and log row to that one worker. |
3679
- | `workspaceId` | Narrows workers and dependent evidence to one workspace; when both selectors are present they intersect. |
3912
+ | `workerId` | Narrows workers and every dependent loop, turn, turn-attached logical inference, specialization, physical request, and log row to that one worker. Workspace-only embeddings are excluded. |
3913
+ | `workspaceId` | Narrows workers plus every logical inference and dependent evidence owned by one workspace, including workspace-only embeddings; when both selectors are present they intersect. |
3680
3914
 
3681
- §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 durable resource coordinates render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; packet files remain byte-identical records of what the model saw.
3915
+ §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log event with its initial and current projection, causal `source`, tags, and structured `attrs`; every exact OPEN/FOLD/log-KILL target effect; the exact Problem on every failed row; each loop's exact terminal result; and every ordered physical provider request. KILLed `turnOps` still produce their chronological `assistant.md` artifacts because curation cannot rewrite what a producer submitted. Each stored packet validates independently: one malformed historical packet remains exact raw evidence with its complete validation error chain and never prevents healthy turns from being projected. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. The reasoning chronology distinguishes readable reasoning content from provider-reported reasoning usage: when tokens were reported but no readable content was returned, it states both facts instead of implying that no reasoning occurred. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and durable resource coordinates render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; valid packet files remain byte-identical records of what the model saw.
3682
3916
 
3683
3917
  §digest-requiem **A requiem is an out-of-band forensic interview, not a worker
3684
3918
  turn.** It cannot execute operations or alter the audited history.
@@ -3701,7 +3935,7 @@ turn.** It cannot execute operations or alter the audited history.
3701
3935
  §tools-resource-discovery **Executable capability discovery uses ordinary
3702
3936
  Plurnk resources.** No generated tool table rides the system packet. Every
3703
3937
  runtime enabled for the current worker with an admitted invocation materializes exactly one
3704
- family document at `worker://~/_plurnk/skills/plurnk/<runtime>.md`. A general runtime's
3938
+ family document at `worker://~/_plurnk/plurnk/<runtime>.md`. A general runtime's
3705
3939
  document contains its {§executor-tool-document}; a runtime with an exact
3706
3940
  {§executor-tool-registry} materializes the same single document — per-target
3707
3941
  child documents do not exist, shown or stored. The family document summarizes
@@ -3731,7 +3965,7 @@ enabled executable; executor enablement is the sole user-configured filter
3731
3965
  shared by discovery and dispatch. A runtime declaration may carry
3732
3966
  `resourcesPath` — its generated-doc root relative to the worker's generated
3733
3967
  subtree ({§worker-generated-subtree}). Absent, its docs live in the internal
3734
- `_plurnk/skills/plurnk` namespace; present (attached MCP families: `/tools`),
3968
+ `_plurnk/plurnk` namespace; present (attached MCP families: `/tools`),
3735
3969
  the family document materializes at `_plurnk` + that root in the
3736
3970
  worker's private entry space. Turn 0 surveys the families (`## FIND0 [+init,+tools]
3737
3971
  (worker://~/_plurnk/tools/*.md)`, one row per
@@ -3744,6 +3978,57 @@ unasked.
3744
3978
  Attached tools are capabilities like every other runtime; the model never
3745
3979
  learns an origin.
3746
3980
 
3981
+ §members-functionality **File membership is one Worker Functionality family.**
3982
+ Core registers the `members` family with the coordinator ({§functionality-coordinator}):
3983
+ the model, the client, and the operator learn one surface — `list | discover | add |
3984
+ enable | disable | remove`, `worker.members.<verb>` for the client, `## EXEC0 [members]
3985
+ (<verb>)` for the model — for what the model may see, exactly as they do for skills and
3986
+ MCP servers. A definition is one gitignore-style glob, `{ glob }`, relative to the project
3987
+ root; a leading `!` excludes matching members, and an exclusion wins over every inclusion.
3988
+ The coordinator's provenance (`service-configuration`, `client-action`, `model-proposal`)
3989
+ rides the definition; its alias is a short name, suggested from the glob. `list` shows each
3990
+ definition with what it resolved to — `include` or `exclude`, the pattern, the members it
3991
+ admits or removes (count and a bounded sample), and for a model's inclusion the matches the
3992
+ repository's ignore rules refused — so the model sees what its glob did and adapts.
3993
+ `discover` is introspection, never a catalog: a path answers why it is or is not visible
3994
+ (tracked, included by which pattern, a creation record, excluded by which `!glob`, ignored,
3995
+ untracked, absent); a glob previews what `add` would include or exclude. Names only, never
3996
+ content; nothing is added.
3997
+
3998
+ §members-configuration *Available definitions.* The operator's `PLURNK_MEMBERS_<ALIAS>=<glob>`
3999
+ (`!glob` excludes) and `PLURNK_MEMBERS_ENABLED=[…]` (absent or `[]` enables none) are the
4000
+ service-origin definitions, the shape `PLURNK_MCP_*` already has; an empty glob, a bare `!`,
4001
+ or an unknown enabled alias fails the daemon at boot.
4002
+
4003
+ §members-model-scope *The model's authority.* A model's `add` is admitted against
4004
+ `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` in the file-creation lattice `none < root <
4005
+ namespace`, narrowed by `settings.membersModelScope` (most restrictive wins). Shipped `none`
4006
+ refuses every model definition — inclusion or exclusion — as `403
4007
+ members/functionality/model-scope`, naming `git add` and the operator's `/members add` as
4008
+ the paths that remain; `root` admits patterns inside the root; `namespace` admits `../` too.
4009
+ `auto` loops self-approve proposals, so the ceiling — not the proposal — is the guard
4010
+ ({§membership-baseline}). The coordinator hands `admit` the caller (`action` | `operation`)
4011
+ so the family bounds the model without a second grammar.
4012
+
4013
+ §members-projection *One overlay.* Definitions are desired state per Worker
4014
+ ({§functionality-state}); the workspace overlay (`workspace_constraints`) is their union
4015
+ across every worker of the workspace (ruling (a)): inclusions union and an exclusion wins.
4016
+ A child's birth snapshot counts as its own desire: a parent's `disable` or `remove`
4017
+ withdraws nothing the child still holds, and a file goes dark only when no worker of the
4018
+ workspace holds an inclusion for it. Human-authored definitions project with source
4019
+ `members`, model-proposed ones with source `model`; the same pattern from both keeps
4020
+ `members`. A `model` inclusion is a pattern scan like a human one but never admits a path
4021
+ the repository ignores ({§membership-model-universe}). The engine's creation records
4022
+ (`source: "create"`, {§fs-create-record}) are not definitions: the projection never
4023
+ overwrites or retires them. Projection happens at the family's publication commit and
4024
+ re-resolves membership; a Worker cooling changes nothing, because desired state is
4025
+ durable. Each enabled definition is one generated document at
4026
+ `worker://~/_plurnk/members/<alias>.md` ({§functionality-documents}) — its glob, origin,
4027
+ provenance, and what it resolved to — surveyed at turn 0 like every family's enabled
4028
+ definitions ({§actor-boundary-catalog-preview}), so the model sees why a file is or is
4029
+ not a member before it asks. There is no other membership path: the client's `/members`
4030
+ verbs are these verbs.
4031
+
3747
4032
  §skills-functionality **Agent Skills are one Worker Functionality family.**
3748
4033
  Core registers the `skills` family with the coordinator ({§functionality-coordinator});
3749
4034
  its adapter owns protocol truth for standard Agent Skills and nothing else. A
@@ -3811,15 +4096,16 @@ model turn while an unchanged set dispatches nothing. The model manages skills
3811
4096
  only through the generated `EXEC [skills]` family
3812
4097
  ({§functionality-model-projection}); it is never taught a package manager.
3813
4098
 
3814
- The catalog describes this worker's Functionality, not temporary authority. Loop
3815
- mode remains a dispatch concern: an ask-mode EXEC receives the ordinary exact
3816
- 403 restriction instead of requiring a second per-loop documentation overlay.
4099
+ The catalog describes this worker's Functionality under its durable capability
4100
+ ceilings. Turn0 narrows its surveys and examples through the current loop policy,
4101
+ and a direct denied attempt receives the same exact 403 from dispatch rather
4102
+ than a second documentation policy.
3817
4103
  Optional non-EXEC operations remain a separate `## Enabled Optional Operations`
3818
4104
  section because they are language extensions rather than executable tools.
3819
4105
 
3820
4106
  ### §schemes user.schemes — the resource directory
3821
4107
 
3822
- §schemes-directory A `## Resources` section renders in the system slot **after the policy sections** — a terse directory of the scheme families available to this worker, 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 as the worker-private skill `worker://~/_plurnk/skills/plurnk/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+skills] (worker://~/_plurnk/skills/plurnk/*.md)` survey ({§skills-functionality}), keeping the raw packet free of doc links. Meta-owned `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. The directory advertises the loop's **resolved** scheme set ({§manifest-flag-affinity}): a flag-inactive scheme (`noWeb`, `noInteraction`, ask-mode exclusion) contributes no example — the packet never baits an operation the dispatch gate will refuse. Materialized pull-docs remain worker state: residency owns generated documents, and a differently-flagged later loop on the same worker finds them in place.
4108
+ §schemes-directory A `## Resources` section renders in the system slot **after the policy sections** — a terse directory of the scheme families available to this worker, 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 as the worker-private skill `worker://~/_plurnk/plurnk/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+skills] (worker://~/_plurnk/plurnk/*.md)` survey ({§skills-functionality}), keeping the raw packet free of doc links. Meta-owned `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. The directory includes only examples admitted by the effective worker-level capability layers, and Turn0 further narrows discovery through its loop policy using the same resolver ({§capability-admission}); the packet never baits an operation its own admission path will refuse. Materialized pull docs remain worker state, while their discoverability and execution remain policy-bound.
3823
4109
 
3824
4110
  ### §inject system.inject — the operator injection
3825
4111
 
@@ -3830,7 +4116,7 @@ section because they are language extensions rather than executable tools.
3830
4116
  §policy-sections One section rides the system slot **after the definition and before capability teaching**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}). Policy is 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. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker://~/_plurnk/agents.md` entry ({§turn0-agents-stunt}); all other reference material is skills under the worker's private skills tree ({§skills-functionality}).
3831
4117
 
3832
4118
  On first run, and only when `$XDG_CONFIG_HOME/plurnk` itself is absent, the service seeds
3833
- `AGENTS.md` from `@plurnk/plurnk-meta/PLURNK_PERSONALITY.md` ({§teaching-corpus}).
4119
+ `AGENTS.md` from `@plurnk/plurnk-meta/POLICY.md` ({§teaching-corpus}).
3834
4120
  It reads that required source before creating the service home; a failed read
3835
4121
  surfaces with its cause and leaves no apparently initialized home.
3836
4122
  After that bootstrap the file is user-owned: edits and deletion persist, and a
@@ -3848,36 +4134,44 @@ created by that attempt. Unknown legacy members or simultaneous
3848
4134
  legacy/canonical state fail without guessing. No dual read or dual write survives
3849
4135
  the transition.
3850
4136
 
3851
- §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. Every published pull doc carries an exact H2 `Summary` for ordinary catalog projection. `SchemeRegistry.teach(workerId)` renders the effective directory, `SchemeRegistry.docs(workerId)` resolves corpus-or-manifest documentation, and `referenceEntries(workerId)` supplies the current `/skills/plurnk/` generated-skill set when core publishes worker Functionality ({§skills-functionality}). One materializer reconciles the worker's private scope exactly: vanished contributions are deleted before current documents are upserted, so an excluded scheme or disabled, detached, replaced, or removed runtime cannot leave a stale model-facing contract.
4137
+ §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. Every published pull doc carries an exact H2 `Summary` for ordinary catalog projection. `SchemeRegistry.teach(workerId)` renders the effective directory, `SchemeRegistry.docs(workerId)` resolves corpus-or-manifest documentation, and `referenceEntries(workerId)` supplies the current `/plurnk/` generated-skill set when core publishes worker Functionality ({§skills-functionality}). One materializer reconciles the worker's private scope exactly: vanished contributions are deleted before current documents are upserted, so an excluded scheme or disabled, detached, replaced, or removed runtime cannot leave a stale model-facing contract.
3852
4138
 
3853
4139
  ### §packet-git-status The Git status section — compact repository state
3854
4140
 
3855
4141
  When Git is admitted for the workspace, `## Git Status` reports the current
3856
- branch, upstream ahead/behind counts, and staged/unstaged/untracked totals. The
4142
+ branch, upstream ahead/behind counts, and staged/unstaged/untracked totals, then
4143
+ one bounded line per non-empty class (at most eight paths, `+K more`): staged,
4144
+ unstaged, `untracked members` — each path with the inclusion pattern that admits it or
4145
+ `created` for a creation record — and `untracked (not members)`, named because such a
4146
+ file is not a member ({§membership-baseline}) and a human must `git add` it or add a
4147
+ members definition before the model can read it. The section never contradicts the
4148
+ catalog: an untracked file a definition admits is named as the member it is. The
3857
4149
  active direct child of a running branch batch additionally receives its assigned
3858
4150
  branch and the requirement to commit any project changes and leave the checkout
3859
4151
  clean before concluding ({§worker-branch-batch-return}); no other worker receives
3860
- that instruction. The section never repeats an unbounded path list. Per-path state belongs to
4152
+ that instruction. The section never carries an unbounded path list. Per-path state belongs to
3861
4153
  the runtime actor's durable causal evidence: its `source=file` row carries
3862
4154
  the exact two-character porcelain `XY` value as `git` metadata when the status
3863
4155
  snapshot names that path. The engine takes one snapshot after membership
3864
4156
  reconciliation and uses it for both projections; no per-file Git process exists.
3865
4157
 
3866
- ### §requirements Recap footer
4158
+ ### §recap Optional Recap footer
3867
4159
 
3868
- The user slot ends with `## Recap`, a compact recency-biased reminder of selected
3869
- operational law already owned by `plurnk.md`. A non-empty `runLoop` / `runTurn`
3870
- `requirements` value overrides the default; otherwise core reads
3871
- `PLURNK_SERVICE_REQUIREMENTS` or the required meta-owned `requirements.md` source
3872
- for every packet. A failed read fails packet assembly with its cause. The footer
3873
- is one projection path and one authored source, not a second language contract.
4160
+ The user slot may end with `## Recap`, a compact recency-biased reminder of
4161
+ selected operational law already owned by `plurnk.md`. A non-empty `runLoop` /
4162
+ `runTurn` `recap` value overrides the default; otherwise core reads
4163
+ `PLURNK_SERVICE_RECAP` or the required meta-owned `recap.md` source for every
4164
+ packet. Empty content intentionally omits the rendered section while retaining
4165
+ one dormant authored source. A failed read fails packet assembly with its cause.
4166
+ The footer is one projection path and one authored source, not a second language
4167
+ contract.
3874
4168
 
3875
4169
  ## §matcher Matcher selection and text regions
3876
4170
 
3877
4171
  Body matchers and text scopes are independent. Matcher prefixes choose a
3878
- dialect (`//` xpath, `/` regex, `$` jsonpath, otherwise glob); they select
3879
- resources and report evidence. A text scope always addresses the exact readable
3880
- text, regardless of mimetype.
4172
+ dialect (`//` xpath, `/` regex, `$` jsonpath, `~` semantic, `&` graph, otherwise
4173
+ glob); they select resources and report evidence. A text scope always addresses
4174
+ the exact readable text, regardless of mimetype.
3881
4175
 
3882
4176
  ### §matcher-dispatch Matcher dispatch
3883
4177
 
@@ -3889,9 +4183,9 @@ One parsed content matcher crosses three ownership layers:
3889
4183
  | `@plurnk/plurnk-schemes/Matcher` | Map framework results and typed failures to the universal scheme-result contract. |
3890
4184
  | Core `Matcher.matchCandidates` | Apply that operation adapter across caller-supplied `{key, content, mimetype}` candidates and preserve source identity. |
3891
4185
 
3892
- §relation-indexed-dialects `~semantic` and `@graph` are indexed relation dialects and never route through
3893
- the content matcher. A graph body is exactly one symbol (`@sym`, `@<sym`, `@>sym`); any other `@…` body is
3894
- refused 400 naming the dialect before an index is consulted. When the candidates' persistent index is still
4186
+ §relation-indexed-dialects `~semantic` and `&graph` are indexed relation dialects and never route through
4187
+ the content matcher. Language admission accepts exactly one graph symbol (`&sym`, `&<sym`, `&>sym`);
4188
+ runtime validation is only a defensive boundary for typed callers. When the candidates' persistent index is still
3895
4189
  deriving, the engine settles the workspace's derivations once and re-runs the selection; a still-incomplete
3896
4190
  index is a 503 that is retryable — never a refusal to wait paired with an instruction to wait. Candidate composition has no dependency on the table that
3897
4191
  stored a resource.
@@ -3905,9 +4199,9 @@ container identity.
3905
4199
 
3906
4200
  | Matcher body | Selected resources | Match evidence |
3907
4201
  | ------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
3908
- | `@<symbol` | In-scope resources that reference `symbol` | Each matching reference's source span |
3909
- | `@>symbol` | In-scope resources defining names referenced by each definition of `symbol` | Each referenced symbol's definition span |
3910
- | `@symbol` | Union of definitions of `symbol`, referrers, and definitions of referenced names | Corresponding definition/reference spans, deduplicated by resource + span |
4202
+ | `&<symbol` | In-scope resources that reference `symbol` | Each matching reference's source span |
4203
+ | `&>symbol` | In-scope resources defining names referenced by each definition of `symbol` | Each referenced symbol's definition span |
4204
+ | `&symbol` | Union of definitions of `symbol`, referrers, and definitions of referenced names | Corresponding definition/reference spans, deduplicated by resource + span |
3911
4205
 
3912
4206
  | Result | HTTP status |
3913
4207
  |---|---|
@@ -3917,6 +4211,12 @@ container identity.
3917
4211
  | Source unparseable for its mimetype | 203 (soft fallback: raw content as text with `reason`) |
3918
4212
  | Dialect unsupported by the resource | 415 |
3919
4213
 
4214
+ §matcher-invalid-expression A malformed matcher Problem identifies the dialect
4215
+ and includes the bounded native parser cause as `diagnostic` when available. Core applies
4216
+ `PLURNK_SERVICE_ERROR_DETAIL_LIMIT` before the cause crosses into the schemes
4217
+ adapter; the Problem offers only the deterministic recovery to revise the
4218
+ expression, never a guess about the intended pattern.
4219
+
3920
4220
  §matcher-dispatch-203-soft-fallback On parse failure, 203 returns raw content as the text primitive with `reason`
3921
4221
  so the model can use ordinary text retrieval or repair the source.
3922
4222
 
@@ -3946,7 +4246,7 @@ resources according to {§find-result-projection}.
3946
4246
  | jsonpath `$.path` | resources whose deep JSON resolves the path | canonical locator plus exact/enclosing text region when honest |
3947
4247
  | xpath `//sel` | resources whose deep XML resolves the selector | canonical locator plus exact/enclosing text region when honest |
3948
4248
  | `~`semantic `~q` | resources ranked by indexed chunks | chunk text region when available |
3949
- | `@`graph `@<sym` | resources with matching symbol relations | symbol text region when available |
4249
+ | `&`graph `&<sym` | resources with matching symbol relations | symbol text region when available |
3950
4250
 
3951
4251
  Match evidence is navigation evidence, never an implicit body projection. The
3952
4252
  model uses broad FIND to select and page resources, exact FIND to page that