@plurnk/plurnk-service 1.4.0 → 1.5.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 (227) hide show
  1. package/.env.defaults +20 -23
  2. package/INSTALL.md +6 -5
  3. package/README.md +1 -0
  4. package/SPEC.md +250 -149
  5. package/dist/Paths.d.ts.map +1 -1
  6. package/dist/Paths.js +2 -3
  7. package/dist/Paths.js.map +1 -1
  8. package/dist/build-info.json +1 -1
  9. package/dist/content/index.d.ts +1 -0
  10. package/dist/content/index.d.ts.map +1 -1
  11. package/dist/content/index.js +1 -0
  12. package/dist/content/index.js.map +1 -1
  13. package/dist/content/line-marker.d.ts +7 -3
  14. package/dist/content/line-marker.d.ts.map +1 -1
  15. package/dist/content/line-marker.js +2 -1
  16. package/dist/content/line-marker.js.map +1 -1
  17. package/dist/content/matcher.d.ts +1 -1
  18. package/dist/content/matcher.d.ts.map +1 -1
  19. package/dist/content/matcher.js +2 -2
  20. package/dist/content/matcher.js.map +1 -1
  21. package/dist/content/read-projector.d.ts +14 -0
  22. package/dist/content/read-projector.d.ts.map +1 -0
  23. package/dist/content/read-projector.js +86 -0
  24. package/dist/content/read-projector.js.map +1 -0
  25. package/dist/content/read-resolve.d.ts +2 -7
  26. package/dist/content/read-resolve.d.ts.map +1 -1
  27. package/dist/content/read-resolve.js +32 -107
  28. package/dist/content/read-resolve.js.map +1 -1
  29. package/dist/core/BranchReceipt.d.ts +0 -1
  30. package/dist/core/BranchReceipt.d.ts.map +1 -1
  31. package/dist/core/BranchReceipt.js +0 -3
  32. package/dist/core/BranchReceipt.js.map +1 -1
  33. package/dist/core/BudgetOverflow.d.ts +0 -3
  34. package/dist/core/BudgetOverflow.d.ts.map +1 -1
  35. package/dist/core/BudgetOverflow.js +3 -15
  36. package/dist/core/BudgetOverflow.js.map +1 -1
  37. package/dist/core/ChannelWrite.d.ts +3 -0
  38. package/dist/core/ChannelWrite.d.ts.map +1 -1
  39. package/dist/core/ChannelWrite.js +2 -2
  40. package/dist/core/ChannelWrite.js.map +1 -1
  41. package/dist/core/ChannelWrite.sql +4 -3
  42. package/dist/core/CoreSchemeServices.d.ts +10 -2
  43. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  44. package/dist/core/CoreSchemeServices.js.map +1 -1
  45. package/dist/core/Dispatcher.d.ts +3 -7
  46. package/dist/core/Dispatcher.d.ts.map +1 -1
  47. package/dist/core/Dispatcher.js +283 -217
  48. package/dist/core/Dispatcher.js.map +1 -1
  49. package/dist/core/Engine.d.ts +19 -12
  50. package/dist/core/Engine.d.ts.map +1 -1
  51. package/dist/core/Engine.js +261 -167
  52. package/dist/core/Engine.js.map +1 -1
  53. package/dist/core/Engine.sql +66 -63
  54. package/dist/core/LogBody.d.ts +2 -1
  55. package/dist/core/LogBody.d.ts.map +1 -1
  56. package/dist/core/LogBody.js +33 -1
  57. package/dist/core/LogBody.js.map +1 -1
  58. package/dist/core/LoopLifecycle.d.ts +1 -2
  59. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  60. package/dist/core/LoopLifecycle.js +1 -4
  61. package/dist/core/LoopLifecycle.js.map +1 -1
  62. package/dist/core/LoopLifecycle.sql +1 -4
  63. package/dist/core/PacketBuilder.d.ts +3 -2
  64. package/dist/core/PacketBuilder.d.ts.map +1 -1
  65. package/dist/core/PacketBuilder.js +16 -16
  66. package/dist/core/PacketBuilder.js.map +1 -1
  67. package/dist/core/StrikeRail.d.ts +5 -1
  68. package/dist/core/StrikeRail.d.ts.map +1 -1
  69. package/dist/core/StrikeRail.js +4 -3
  70. package/dist/core/StrikeRail.js.map +1 -1
  71. package/dist/core/TerminalResult.d.ts +16 -0
  72. package/dist/core/TerminalResult.d.ts.map +1 -0
  73. package/dist/core/TerminalResult.js +49 -0
  74. package/dist/core/TerminalResult.js.map +1 -0
  75. package/dist/core/caps/CapsResolve.d.ts +5 -1
  76. package/dist/core/caps/CapsResolve.d.ts.map +1 -1
  77. package/dist/core/caps/CapsResolve.js +8 -4
  78. package/dist/core/caps/CapsResolve.js.map +1 -1
  79. package/dist/core/caps/DbChannelCaps.d.ts +1 -1
  80. package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
  81. package/dist/core/caps/DbChannelCaps.js +6 -4
  82. package/dist/core/caps/DbChannelCaps.js.map +1 -1
  83. package/dist/core/caps/DbEntryCaps.d.ts +1 -1
  84. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
  85. package/dist/core/caps/DbEntryCaps.js +14 -4
  86. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  87. package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
  88. package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
  89. package/dist/core/caps/DbNotifyCaps.js +6 -4
  90. package/dist/core/caps/DbNotifyCaps.js.map +1 -1
  91. package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -6
  92. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
  93. package/dist/core/caps/DbSubscriptionCaps.js +27 -13
  94. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
  95. package/dist/core/caps/DbTagCaps.d.ts +1 -1
  96. package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
  97. package/dist/core/caps/DbTagCaps.js +6 -4
  98. package/dist/core/caps/DbTagCaps.js.map +1 -1
  99. package/dist/core/caps/SchemeCtxImpl.d.ts +6 -1
  100. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
  101. package/dist/core/caps/SchemeCtxImpl.js +6 -6
  102. package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
  103. package/dist/core/fork.sql +2 -2
  104. package/dist/core/git-iso.d.ts +3 -2
  105. package/dist/core/git-iso.d.ts.map +1 -1
  106. package/dist/core/git-iso.js +27 -12
  107. package/dist/core/git-iso.js.map +1 -1
  108. package/dist/core/git-membership.d.ts +1 -0
  109. package/dist/core/git-membership.d.ts.map +1 -1
  110. package/dist/core/git-membership.js +86 -24
  111. package/dist/core/git-membership.js.map +1 -1
  112. package/dist/core/git-state.d.ts +8 -1
  113. package/dist/core/git-state.d.ts.map +1 -1
  114. package/dist/core/git-state.js +35 -16
  115. package/dist/core/git-state.js.map +1 -1
  116. package/dist/core/namespace.d.ts +1 -0
  117. package/dist/core/namespace.d.ts.map +1 -1
  118. package/dist/core/namespace.js +20 -0
  119. package/dist/core/namespace.js.map +1 -1
  120. package/dist/core/optimistic-settlement.d.ts +2 -0
  121. package/dist/core/optimistic-settlement.d.ts.map +1 -0
  122. package/dist/core/optimistic-settlement.js +14 -0
  123. package/dist/core/optimistic-settlement.js.map +1 -0
  124. package/dist/core/packet-wire.d.ts +1 -1
  125. package/dist/core/packet-wire.d.ts.map +1 -1
  126. package/dist/core/packet-wire.js +81 -35
  127. package/dist/core/packet-wire.js.map +1 -1
  128. package/dist/core/results.d.ts +4 -2
  129. package/dist/core/results.d.ts.map +1 -1
  130. package/dist/core/results.js +6 -0
  131. package/dist/core/results.js.map +1 -1
  132. package/dist/core/scheme-types.d.ts +0 -12
  133. package/dist/core/scheme-types.d.ts.map +1 -1
  134. package/dist/core/scheme-types.js.map +1 -1
  135. package/dist/core/worker-ops.sql +4 -4
  136. package/dist/core/workspace-settings.js +1 -1
  137. package/dist/core/workspace-settings.js.map +1 -1
  138. package/dist/digest/Digest.d.ts.map +1 -1
  139. package/dist/digest/Digest.js +236 -74
  140. package/dist/digest/Digest.js.map +1 -1
  141. package/dist/digest/digest.sql +9 -5
  142. package/dist/schemes/Exec.d.ts +4 -4
  143. package/dist/schemes/Exec.d.ts.map +1 -1
  144. package/dist/schemes/Exec.js +56 -33
  145. package/dist/schemes/Exec.js.map +1 -1
  146. package/dist/schemes/ExecOutputScheme.d.ts +4 -5
  147. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  148. package/dist/schemes/ExecOutputScheme.js +12 -20
  149. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  150. package/dist/schemes/File.d.ts +1 -3
  151. package/dist/schemes/File.d.ts.map +1 -1
  152. package/dist/schemes/File.js +11 -19
  153. package/dist/schemes/File.js.map +1 -1
  154. package/dist/schemes/Log.d.ts +5 -5
  155. package/dist/schemes/Log.d.ts.map +1 -1
  156. package/dist/schemes/Log.js +74 -172
  157. package/dist/schemes/Log.js.map +1 -1
  158. package/dist/schemes/Log.sql +20 -13
  159. package/dist/schemes/Prompt.d.ts +2 -3
  160. package/dist/schemes/Prompt.d.ts.map +1 -1
  161. package/dist/schemes/Prompt.js +1 -4
  162. package/dist/schemes/Prompt.js.map +1 -1
  163. package/dist/schemes/Skill.d.ts +2 -3
  164. package/dist/schemes/Skill.d.ts.map +1 -1
  165. package/dist/schemes/Skill.js +0 -3
  166. package/dist/schemes/Skill.js.map +1 -1
  167. package/dist/schemes/Worker.d.ts +5 -5
  168. package/dist/schemes/Worker.d.ts.map +1 -1
  169. package/dist/schemes/Worker.js +92 -81
  170. package/dist/schemes/Worker.js.map +1 -1
  171. package/dist/schemes/_entry-crud.d.ts +2 -1
  172. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  173. package/dist/schemes/_entry-crud.js +14 -1
  174. package/dist/schemes/_entry-crud.js.map +1 -1
  175. package/dist/schemes/_entry-crud.sql +9 -3
  176. package/dist/schemes/_entry-find.d.ts +37 -11
  177. package/dist/schemes/_entry-find.d.ts.map +1 -1
  178. package/dist/schemes/_entry-find.js +141 -153
  179. package/dist/schemes/_entry-find.js.map +1 -1
  180. package/dist/schemes/_entry-ops.d.ts +9 -5
  181. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  182. package/dist/schemes/_entry-ops.js +12 -73
  183. package/dist/schemes/_entry-ops.js.map +1 -1
  184. package/dist/schemes/_entry-ops.sql +1 -2
  185. package/dist/schemes/_entry-semantic.d.ts +5 -7
  186. package/dist/schemes/_entry-semantic.d.ts.map +1 -1
  187. package/dist/schemes/_entry-semantic.js +10 -31
  188. package/dist/schemes/_entry-semantic.js.map +1 -1
  189. package/dist/schemes/_entry-semantic.sql +2 -2
  190. package/dist/schemes/_search-index.d.ts.map +1 -1
  191. package/dist/schemes/_search-index.js +6 -4
  192. package/dist/schemes/_search-index.js.map +1 -1
  193. package/dist/server/BranchBatches.d.ts +1 -0
  194. package/dist/server/BranchBatches.d.ts.map +1 -1
  195. package/dist/server/BranchBatches.js +1 -0
  196. package/dist/server/BranchBatches.js.map +1 -1
  197. package/dist/server/Daemon.d.ts +5 -7
  198. package/dist/server/Daemon.d.ts.map +1 -1
  199. package/dist/server/Daemon.js +222 -54
  200. package/dist/server/Daemon.js.map +1 -1
  201. package/dist/server/DaemonModule.d.ts +3 -3
  202. package/dist/server/DaemonModule.d.ts.map +1 -1
  203. package/dist/server/branch-batch.sql +3 -1
  204. package/dist/server/client-input.d.ts +2 -1
  205. package/dist/server/client-input.d.ts.map +1 -1
  206. package/dist/server/client-input.js +7 -1
  207. package/dist/server/client-input.js.map +1 -1
  208. package/dist/server/drain.sql +6 -5
  209. package/dist/server/envelope.d.ts +2 -2
  210. package/dist/server/envelope.d.ts.map +1 -1
  211. package/dist/server/envelope.js +0 -1
  212. package/dist/server/envelope.js.map +1 -1
  213. package/dist/server/envelope.sql +1 -2
  214. package/dist/server/lifecycle-recovery.sql +34 -1
  215. package/dist/server/logEntry.d.ts +1 -1
  216. package/dist/server/logEntry.d.ts.map +1 -1
  217. package/dist/server/logEntry.js +2 -1
  218. package/dist/server/logEntry.js.map +1 -1
  219. package/dist/service.d.ts.map +1 -1
  220. package/dist/service.js +13 -1
  221. package/dist/service.js.map +1 -1
  222. package/migrations/001_schema.sql +238 -125
  223. package/package.json +48 -46
  224. package/dist/matrix/live-specimen.d.ts +0 -9
  225. package/dist/matrix/live-specimen.d.ts.map +0 -1
  226. package/dist/matrix/live-specimen.js +0 -37
  227. package/dist/matrix/live-specimen.js.map +0 -1
package/SPEC.md CHANGED
@@ -30,7 +30,7 @@ flowchart LR
30
30
  | **turn** | Core | One engine scheduling unit (or one client-op scheduling unit). A model turn sends one assembled prompt through one or more emission attempts and admits at most one response. Many turns may belong to one loop. Identity: `(loop_id, sequence)`. |
31
31
  | **op** | Model/core | One DSL operation the model emits, parsed into a `PlurnkStatement`. One admitted turn produces zero or more ops. |
32
32
  | **statement** | Model/core | A parsed op: the `PlurnkStatement` AST from `@plurnk/plurnk-contracts`. |
33
- | **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an actionless `op='error'` row ({§operation-results}). |
33
+ | **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an actionless `op='error'` row ({§operation-results}). Actionless artifacts carry no fabricated operation. |
34
34
  | **dispatch** | Core | Routing a statement to its scheme's op handler. |
35
35
  | **AG-UI Run** | AG-UI protocol | A client request/stream envelope identified by the client's `runId`. A message or resume AG-UI Run binds to one core loop; a management-action AG-UI Run may complete without creating a core loop. |
36
36
  | **AG-UI thread** | AG-UI protocol | Conversation identity. Within an explicitly selected workspace, `threadId` resolves to one conversation worker. |
@@ -75,11 +75,15 @@ These are the complete strike sources:
75
75
 
76
76
  | Strike source | Exact trigger | Model-visible occurrence |
77
77
  |---------------------|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
78
- | Hard result | An admitted operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `501`. | The originating failure row. |
78
+ | Hard result | An admitted non-`EXEC` operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `501`. | The originating failure row. |
79
79
  | Grinder | Packet overflow caused a grinder fold or admitted hard-recovery turn ({§grinder-strike-coupling}). | The exact overflow Problem row. |
80
80
  | Terminal steering | An idle `SEND[102]` or a final disposition refused at 409 sets the turn's steering ruling ({§send}). | The idle rail row or refused SEND row. |
81
81
  | Cycle | The configured consecutive fingerprint pattern repeats. | None; cycle detection itself is private engine accounting. |
82
82
 
83
+ `EXEC` results remain exact model-visible evidence but are always soft: an
84
+ executor error is not a PLURNK contract violation. Cycle and terminal steering
85
+ remain independent strike sources.
86
+
83
87
  A struck turn increments the consecutive streak once; a clean admitted turn
84
88
  resets it to zero. Reaching `MAX_STRIKES` terminates at **508 Loop Detected**
85
89
  when the crossing turn is cycle-detected, otherwise **500**. Rejected emission
@@ -122,9 +126,10 @@ real PLURNK loop: the production packet, a model-selected operation, its
122
126
  materialized result, and completion.** Transport-only completions are not
123
127
  conformance evidence. Provider-exposed reasoning must survive in the durable
124
128
  assistant packet and digest; a provider with no private reasoning is valid when
125
- the observable operation cycle succeeds. The maintained procedure runs one
126
- named live specimen deterministically (`npm run test:live:specimen -- <pattern>`
127
- in plurnk-core); the ledger and classification taxonomy live in
129
+ the observable operation cycle succeeds. One package-owned runner executes the
130
+ full tier or exactly one registered specimen (`npm run test:live:specimen --
131
+ <exact test name>` in plurnk-core), rejecting absent and duplicate names before
132
+ execution. The ledger and classification taxonomy live in
128
133
  `plurnk-providers/README.md` and report authorization/credential failures
129
134
  distinct from model failures and repeated stochastic failures separately from
130
135
  stable ones, never with weakened assertions.
@@ -285,7 +290,7 @@ the `plurnk` worker's log; the model sees the shared entry through its own READ.
285
290
  Client-provided workspace documents union with the operator set at the same
286
291
  entry surface.
287
292
 
288
- §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS` foists turn-0 FINDs into the worker's first turn, so a worker opens with a navigable map instead of blank. An enabled preview always executes four orienting surveys: project files (`FIND(*)`), workspace commons (`FIND(worker:///*)`), the worker's own space (`FIND(worker://~/*)`), and kernel docs (`FIND(worker://plurnk/docs/**)`). Folder-capable entry plugins use the same shallow form; a scheme without folder scopes remains recursive. A shallow result is complete, not truncated: direct entries render normally and every deeper first-segment directory renders as an actionable `dir/**` summary with its recursive `items` and `tokens`. The small curated kernel-doc surface remains recursively enumerated, so the opening exemplar demonstrates both `*` and `**`. Every survey executes even when empty because zero results are useful orientation. A positive `N` caps only the file map's rendered rows, using the map's actual direct-entry-plus-directory count; `-1` renders the complete shallow map; unset / `0` disables previews. `log://` is absent because the current worker's log already renders in present mode.
293
+ §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS` foists turn-0 FINDs into the worker's first turn, so a worker opens with a navigable map instead of blank. An enabled preview always executes four orienting surveys: project files (`FIND(*)`), workspace commons (`FIND(worker:///*)`), the worker's own space (`FIND(worker://~/*)`), and kernel docs (`FIND(worker://plurnk/docs/**)<1,-1>`). Folder-capable entry plugins use the same shallow form; a scheme without folder scopes remains recursive. A shallow result renders direct entries normally and every deeper first-segment directory as an actionable `dir/**` summary with its recursive `items` and `tokens`. Ordinary surveys use FIND's markerless first-16 page, whose range metadata reports the requested and returned page against the complete result total; only the small curated kernel-doc surface explicitly selects all. The opening exemplar therefore demonstrates both `*` and `**` without normalizing an all-results override. Every survey executes even when empty because zero results are useful orientation. A positive `N` explicitly caps only the file map's rendered rows, using the map's actual direct-entry-plus-directory count; `-1` enables the ordinary markerless page; unset / `0` disables previews. `log://` is absent because the current worker's log already renders in present mode.
289
294
 
290
295
  ### §machine-processes The machine and its processes: workspace, worker, fork
291
296
 
@@ -466,7 +471,9 @@ sequenceDiagram
466
471
 
467
472
  §worker-branch-batch-return **A child returns commits, never a dirty checkout.** SEND[200], SEND[499], and an already-drained SEND[202] are refused with 409 while the project repository is off the assigned branch or dirty. The model commits or deliberately discards its changes and concludes again. On terminal, the batch records the full result commit and whether it differs from the frozen base, restores the exact original ref and commit, and only then advances. A clean child failure is a completed batch item and does not suppress later siblings; an ambiguous or dirty host failure becomes `recovery_required` and retains exclusivity because restoring would destroy or misattribute work.
468
473
 
469
- §worker-branch-batch-receipt **The parent reconciles; the engine does not merge.** The ordinary child deliverable remains the model's exact SEND body. Its pushed termination delta and pull-side `READ(worker://child)` append a bounded branch receipt: branch, item outcome, and the abbreviated result commit (`PLURNK_SERVICE_BRANCH_RECEIPT_REVISION_CHARS`; the database retains the full id). Branch refs remain after the batch. The parent chooses inspection, cherry-pick, merge, rejection, or deletion with ordinary Git tools.
474
+ The active direct child's `Git Status` names its assigned branch and states the commit-and-clean return condition. No ordinary worker receives ambient commit or authorship policy; commit identity remains host-owned and outside model teaching. {§packet-git-status}
475
+
476
+ §worker-branch-batch-receipt **The parent reconciles; the engine does not merge.** The ordinary child deliverable remains the model's exact SEND result. Its pushed termination delta and pull-side `READ(worker://child)` append a bounded branch receipt to the presented body without changing that result: branch, item outcome, and the abbreviated result commit (`PLURNK_SERVICE_BRANCH_RECEIPT_REVISION_CHARS`; the database retains the full id). Branch refs remain after the batch. The parent chooses inspection, cherry-pick, merge, rejection, or deletion with ordinary Git tools.
470
477
 
471
478
  §worker-branch-batch-recovery **Recovery follows durable ownership.** `branch_batches`, their ordered items, the project-repository snapshot, and result tips are schema state, not process memory. Generic boot recovery never starts their queued loops. A crash before sealing fails the unstarted batch. A queued partial preflight is rolled back only when every created ref still equals its frozen base, then retried. A running child is never replayed: its loop settles under the ordinary owner-loss rule; if the checkout is clean and either on the assigned branch or the exact original position, the committed tip is retained, the original restored, that item marked interrupted, and queued siblings continue. Any mismatch becomes `recovery_required` and keeps the workspace stopped for operator correction.
472
479
 
@@ -477,15 +484,14 @@ The remaining worker surfaces are:
477
484
  - §worker-scheme-cap **Cap** — `PLURNK_SERVICE_WORKSPACE_WORKERS_MAX_ACTIVE` ceilings the *concurrent* active workers per workspace (a worker with a non-terminal loop); a spawn or fork past it fails hard (508 — no queue, no retry), irc exempt; `-1` disables it. The fork-bomb brake, sized for workspaces that live for months.
478
485
  - §worker-scheme-collect **Collect** — a worker's loop reaching a terminal status
479
486
  surfaces to its sisters as an ambient delta ({§env-delta}): a `SEND` from
480
- `worker://<name>` carrying the loop's deliverable the `SEND[200]` body, or
481
- for an abandonment the reason. A **2xx deliverable is born OPEN** (its body
487
+ `worker://<name>` carrying the loop's exact terminal operation result. A
488
+ **2xx deliverable is born OPEN** (its body
482
489
  materialized into the parent's packet, not hidden behind a fold): a child's
483
490
  success must reach the parent open and awakening, never a bodyless row. An
484
- abandonment (non-2xx) surfaces folded. Every death-path is stamped uniformly,
491
+ non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly,
485
492
  so no termination is silent; collection is the shared world moving, never a
486
493
  verb. The **pull** side mirrors the push: a path-absent
487
- `READ(worker://<name>)` collects the same deliverable on demand the latest
488
- loop's terminal message (the result, or the abandonment reason) for a
494
+ `READ(worker://<name>)` collects that same result on demand for a
489
495
  concluded worker; a worker **still running** has not delivered, so the READ
490
496
  returns **425** (Too Early) and the turn's bare `SEND[102]` **becomes a
491
497
  parked loop (202) on the join** ({§join-blocking-collect}) until the worker
@@ -604,7 +610,9 @@ parent edge as the child's result.
604
610
  §worker-lifecycle-terminal-result **Terminal truth is a result, not a lifecycle code.** `loops.terminal_result`
605
611
  stores the exact universal operation result. A failure therefore retains its
606
612
  RFC 9457 Problem Details and exact status through persistence, restart,
607
- parent collection, and `loop/terminated`. The older constrained `loops.status`
613
+ parent collection, and `loop/terminated`; successful terminal SEND content and
614
+ mimetype remain in the same result. Cancellation markers and branch receipts
615
+ are derived presentation, never a second stored outcome. The constrained `loops.status`
608
616
  column remains only the scheduler's compact lifecycle projection: known
609
617
  terminal classes remain themselves, other 2xx/3xx statuses project to `200`,
610
618
  and other 4xx/5xx statuses project to `500`; exact `202` is forbidden because
@@ -637,6 +645,7 @@ boundary.
637
645
  - §worker-lifecycle-no-resurrection **A cancelled worker is not resurrected by its own torn-down work.** A stream conclusion delivered to a cancelled, idle worker starts no fresh drain: an aborted (499) conclusion is skipped, and a straggler that concluded cleanly surfaces its deliverable as an environment delta ({§env-delta}), never a revived loop. The cancel was deliberate; only an explicit `runLoop` request resumes the worker.
638
646
  - §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** When a backgrounded stream concludes, the daemon routes it through the same inject seam as any loop source ({§actor-boundary-passive-wake}): an active worker folds the conclusion into its next turn; a worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) **awakens that loop in place** — the blocked loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. The result is never lost: a blocked loop sleeps rather than ending, and the stream's status-transition is the arrival ({§actor-boundary-passive-wake}) that wakes it; on resume it reads the concluded stream's own state, not a synthetic prompt.
639
647
  - §worker-lifecycle-child-wake **A child worker concluding wakes a parent blocked on it — the topology join.** `worker://` spawn/fork records `parent_worker_id` ({§lifecycle-terms}). When a worker's drain exits having **concluded** — no `202`-blocked loop, no open stream — the daemon resumes its parent **in place** if the parent is blocked on the join (`#onDrainExit` → the shared `#wakeParkedWorker`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and blocks (`SEND[202]`) is woken the moment its child finishes; on resume it reads the child's deliverable from the {§worker-scheme-collect} delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself blocked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child workers are the same kind of "live thing a worker holds," driving premature-terminate ({§send-premature-terminate}), the wake edge, and the collect delta identically. A worker conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its block commits), `#wakeParkedWorker` finds it not-yet-slept and records an **owed wake**, which the drain honors when the parent blocks — so a wait awaiting workers **always returns**, never dead-blocks on a conclude-before-block race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a wait open.)
648
+ - §worker-optimistic-settlement **Asynchronous settlement receives one bounded worker-local opportunity before model dispatch.** An initiating turn lets only the streams it started settle before its terminal SEND; separately, a stream or direct-child conclusion persists and publishes immediately but holds the parked worker's single `202→100` requeue while another stream or direct child remains live. Both use `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`, shipped at five seconds; zero disables the opportunity. The wake hold ends as soon as no sibling obligation remains, never extends its original deadline, and coalesces every conclusion that lands within it into one requeue. With no sibling obligation the wake is immediate; at the deadline, surviving work follows the ordinary monitored lifecycle. A conclusion that lands after provider dispatch begins retains its next wake, while poll, park-deadline, prompt, and operator wakes never open this hold. Only packet/provider dispatch waits: terminal state, client events, cancellation, and child execution do not. One redaction-safe span records elapsed time, quiescence versus deadline, and conclusion count without entering the packet.
640
649
  - §worker-lifecycle-idle-is-concluded **An idle worker concludes; it does not park.** A loop is idle only when it has neither live obligations nor completed results awaiting their first packet. A live child or stream blocks a `SEND[202]` join; a completed stream, child result, or same-turn retrieval continues directly to the next packet where it is observed. Only after those sets are drained does `SEND[202]` resolve like `SEND[200]`. There is no held-open idle loop and no `loop/quiesced` soft signal. A concluded worker is durable working history and an addressed arrival reawakens it as a new loop.
641
650
  - §worker-lifecycle-no-lost-loop **A loop is never stranded by a drain's exit.** A drain relinquishes its registry slot only after a lock-held re-claim confirms the queue is empty; a loop enqueued during that teardown is either re-claimed by the exiting drain or claimed by a fresh drain that a later inject starts. The relinquish and the start are serialized, so neither the lost-loop hang nor a transient double-drain can occur.
642
651
  - §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.
@@ -650,11 +659,11 @@ Author-facing contract: [`@plurnk/plurnk-providers`](../plurnk-providers/SPEC.md
650
659
 
651
660
  ### §provider-surface Consumption surface
652
661
 
653
- Three entry points:
662
+ Three current entry points:
654
663
 
655
664
  - §provider-surface-generate `provider.generate(args)` — once per provider attempt. Core supplies the complete messages, worker/turn coordinates, generation envelope, optional local grammar, and first-party metadata. A successful `ProviderResponse` reaches emission admission; a `ProviderError.attempt` is failed evidence under {§provider-interrupted-attempt}. Core persists normalized call metadata and forensic response fields and relays encrypted-reasoning items only from an admitted response ({§encrypted-reasoning-carrier}).
656
665
  - §provider-surface-prompt-measurement `provider.countPromptTokens(messages, signal)` — cancellable measurement of the complete provider request with `exact`, `upper_bound`, or `estimate` provenance. It is used only for provider-physical recovery admission ({§tokenomics-physical-admission}); model-facing stored and rendered weights use the provider-agnostic ruler.
657
- - §provider-surface-calculate-cost `provider.calculateCost(usage)` — once per persisted provider attempt carrying usage; estimated USD. Engine aggregates every attempt into `turns.usage_cost_usd`; triggers cascade to `workers.cost_usd` / `workspaces.cost_usd`.
666
+ - §provider-surface-calculate-charge `provider.calculateCharge(usage)` — applies only the exact model's Models.dev rates when the response has no direct monetary field. The frozen `calculateCost` compatibility method is not consumed for reporting.
658
667
 
659
668
  §provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow` (physical token total, or `null` when unknown) and the optional reasoning/completion reserves define the natural prompt partition and physical admission check ({§tokenomics}); `model` identifies persisted turn/provider evidence. Local GBNF boot verification also consumes `constrainsOutput` ({§grammar-enforcement-verified-at-boot}).
660
669
 
@@ -672,15 +681,18 @@ Three entry points:
672
681
 
673
682
  A completed provider exchange is an **emission attempt**, not necessarily an engine turn. The provider transports and observes the model's bytes; ANTLR is the admission authority only after provider completion. Admission asks whether the exchange has a trustworthy frame: its first parsed operation is PLAN, its last parsed operation is a terminal SEND, every hard parse error is bounded between those anchors, and no `unparsedTail` exists. Missing anchors, an error outside the frame, or a boundary-destroying tail rejects the entire exchange regardless of `finishReason`; no recovered prefix dispatches. Parser warnings remain admissible. `finish=length` is forensic evidence of likely truncation, not an independent rejection rule. A provider-declared resource interruption never reaches admission, even when its partial bytes form a complete-looking frame ({§provider-interrupted-attempt}).
674
683
 
675
- Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch, enter the Log, become model history, mint a model-facing error, or reach the engine strike rail. Every response-bearing attempt remains durable in `turn_attempts` with its raw response, parser errors, usage, and cost. The accepted exchange alone completes `turns.packet`; all billed attempts aggregate into the turn's usage while the context gauge reads the latest attempt's prompt usage. Digest exposes rejected evidence as `packetNNN.attemptNNN.rejected.*`.
684
+ 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 attempt carrying its call identity and request attribution; that row closes as response or error, so no issued operation disappears merely because no response returned. Response evidence is durable before parser classification. The accepted exchange alone completes `turns.packet`; all attempt usage aggregates into the turn while the context gauge reads the latest response's prompt usage. Digest exposes rejected evidence as `packetNNN.attemptNNN.rejected.*`.
685
+
686
+ The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED model item under {§model-entry-log-curation} and carries one transient `invalid_emission` Notice whose complete message is: `Your previous response contained an unrecoverable syntax error. No operations were performed. Try again.` No parser diagnostic, attempt count, or rail state becomes model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
676
687
 
677
688
  An admitted frame may contain bounded malformed statements. Parsed operations still dispatch; each malformed statement becomes one durable model-origin `error` row with the parser's exact diagnostic under {§parse-diagnostics} and status 400. These failures are committed before the terminal disposition, participate in the ordinary strike rail, and prevent SEND[200] or an already-drained SEND[202] from concluding before the model sees them in the next packet. This is operation recovery, not provider resampling.
678
689
  The Problem recovery states that only the failed operation needs correction
679
690
  because its parsed siblings were retained; the parser-owned detail states the
680
691
  specific syntax rule.
681
692
 
682
- §invalid-emission-attempts Exhausting the emission-attempt budget terminates
683
- the loop at 500 without spending an engine strike.
693
+ §invalid-emission-attempts Exhausting the emission-attempt budget opens the
694
+ single informed recovery turn above. Consecutive exhaustion of that turn
695
+ terminates the loop at 500 without spending an engine strike.
684
696
 
685
697
  §turn-never-blank An admitted turn whose operation fails — during parsing or
686
698
  dispatch — is categorically different: its failed operation row enters
@@ -704,7 +716,7 @@ shared contract {§plugin-attribution}:
704
716
  | Collection | Immediately before each provider emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. Static declarations and runtime hook results are additive. |
705
717
  | Composition | Core flattens, deduplicates, and sorts the tags. The resulting non-empty array rides `generate({ attributions })`; an empty set omits that provider field. |
706
718
  | Meaning | Core neither verifies nor infers contribution. Tags are plugin-authored folksonomy for telemetry, optimization, attribution, or downstream rules. The `@plurnk/` reservation is the only namespace policy ({§plugin-attribution}). |
707
- | Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Each response-bearing `turn_attempts` row carries its attempt's exact set, so rejected attempts remain distinguishable and a response-less failure is still represented by the request packet. |
719
+ | Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Every pre-I/O `turn_attempts` row carries that call's exact set, including response-less failures. |
708
720
  | Derived reporting | Turn, loop, digest, and client views project the recorded sets. `loop/terminated.attributions` is their deduplicated sorted union and remains separate from provider usage and charge evidence. |
709
721
 
710
722
  Runtime hooks are synchronous and receive only the attempt coordinates. A hook
@@ -917,9 +929,9 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
917
929
  - `SEND[200](path)` — write body into resource (WS message, exec stdin).
918
930
  - `SEND[499](path)` — cancel active subscription ({§stream}).
919
931
 
920
- - §log-uniform-query **Log speaks the universal query contract** — `FIND(log://…)` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~semantic` and `@graph` use the same persistent derivation artifacts and candidate rankers as entries. Results are catalog-shaped items keyed `log:///loop/turn/seq/OP`, and matcher READ retargets per-row READs exactly as entry schemes do. A tag signal filters candidates by the model's own region tags ({§log-region-tagging}). Log remains an event stream in storage; uniformity begins at its readable projection and search attachment, not by forcing logs into the entries table.
921
- - §find-source-agnostic **The content matcher is source-agnostic** — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND/READ with every content dialect works uniformly across schemes BY CONSTRUCTION `EntryFind` and `Log.find` run the ONE shared primitive rather than re-implementing per scheme. This is the query-layer half of the log-uniformity decision (Q3, Option B): log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
922
- - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{path?,region?}`. `path` preserves a structural locator. `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Multiple findings on one resource remain one FIND/READ result; exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. The engine never fabricates a region or guesses which surgical READ the model wants.
932
+ - §log-uniform-query **Log speaks the universal query contract** — `FIND(log://…)` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~semantic` and `@graph` use the same persistent derivation artifacts and candidate rankers as entries. Broad results are catalog-shaped items keyed `log:///loop/turn/seq/OP`; exact matcher results are flat locations ({§find-result-projection}). A tag signal filters candidates by the model's own region tags ({§log-region-tagging}). Log remains the core event ledger rather than duplicating rows into `entries`; its core-private storage adapter supplies one complete channel-and-tag representation to the same READ projector. That adapter is not a plugin seam and grants no protocol scheme an alternate READ path.
933
+ - §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.
934
+ - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{locator?,region?}`. `locator` preserves a structural address without overloading the resource row's `path`; `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. FIND alone decides whether that grouped selection projects as resource rows or flat locations ({§find-result-projection}); the engine never fabricates a region or guesses which surgical READ the model wants.
923
935
 
924
936
  `SEND[410](path[#fragment])` also deletes the target entry/channel — an implemented side-effect, NOT taught to the model and with no live/demo surface. The model-facing delete idiom is KILL ({§move}).
925
937
 
@@ -956,11 +968,25 @@ The optional engine-/daemon-populated capabilities (the notifiers, `injectWorker
956
968
  Engine → scheme guarantees:
957
969
 
958
970
  - `ctx` is fresh per call. No mutation across calls.
959
- - FIND or matcher READ on a `category: "data"` scheme with no custom `find()`
960
- invokes its optional `prepareFind()` and then the standard entry selection.
961
- Preparation owns discovery/materialization only; query semantics remain
962
- universal. The prepared write and the query resolve through one canonical
963
- entry identity, including every component owned by {§scheme-address}.
971
+ - §universal-read-composition **Exact READ has one composition.** Core resolves
972
+ canonical identity and owner once, gives a data scheme its optional
973
+ `prepareRepresentation({ target, pathname })` opportunity, reads the complete
974
+ canonical channels and tags, selects the authored channel, applies binary and
975
+ text-coordinate rules, and finally composes that channel's durable producer
976
+ result. Preparation receives neither fragment nor `lineMarker`; finite work
977
+ returns `200`, while only a retained live representation may return `102`
978
+ ({§read-preparation}). No public handler can replace READ.
979
+ - Exact FIND uses the same resolved identity and representation preparation
980
+ before standard entry selection, then composes the exact default channel's
981
+ durable producer result with the core-owned query projection. Broad FIND may invoke a custom `find()` for
982
+ genuinely protocol-owned candidate enumeration, or `prepareFind()` followed
983
+ by the standard catalog query. Acquisition never owns matcher, pagination,
984
+ or result-unit semantics. Every prepared write and query preserves all
985
+ identity components owned by {§scheme-address}.
986
+ - COPY/MOVE source selection resolves and prepares that same canonical
987
+ representation before selecting a channel. Its independent source scope
988
+ remains raw transfer semantics—markerless means the complete channel rather
989
+ than READ's preview—and is structurally unavailable to the producer.
964
990
  - `ctx.writer` reflects the actual writer at this dispatch.
965
991
  - §scheme-surface-writableby-403 `manifest.writableBy` is checked BEFORE invocation; engine returns 403 directly on exclusion.
966
992
  - `ctx.signal` is wired to the worker's AbortController ({§provider-guarantees-signal-wired}).
@@ -1033,10 +1059,10 @@ plurnk-service is mimetype-illiterate. Engine hands channel content + mimetype l
1033
1059
 
1034
1060
  §mimetype-owned-lifecycle `Daemon` owns and disposes the `Mimetypes` instance
1035
1061
  it constructs. A constructor-injected instance remains caller-owned. Shutdown
1036
- quiesces model work, awaits derivation warming, then disposes the daemon-owned
1037
- instance exactly once; mimetype teardown failures retain their causes and join
1038
- the same aggregate as module and scheme shutdown failures. A pre-start or
1039
- repeated stop does not acquire or dispose resources.
1062
+ quiesces model work, cancels and settles active derivation warming, then
1063
+ disposes the daemon-owned instance exactly once; mimetype teardown failures
1064
+ retain their causes and join the same aggregate as module and scheme shutdown
1065
+ failures. A pre-start or repeated stop does not acquire or dispose resources.
1040
1066
 
1041
1067
  §mimetype-classification-consumption Every engine-owned binary decision uses
1042
1068
  the configured `Mimetypes.classify()` path. An installed handler declaration
@@ -1211,40 +1237,68 @@ A `file:///` member EDIT diverges from this immediate-write contract: it diffs a
1211
1237
 
1212
1238
  ### §read READ
1213
1239
 
1214
- AST: `{ op: "READ", target, body: MatcherBody | null, signal: tags | null, lineMarker? }`.
1240
+ AST: `{ op: "READ", target, body: null, signal: tags | null, lineMarker? }`.
1215
1241
 
1216
1242
  - §read-read-content Returns channel content and mimetype.
1217
1243
  - §read-read-404 Returns 404 when the channel is absent.
1218
- - `body` is a resource predicate dispatched per {§matcher-dispatch}.
1219
- - §read-selection-projection `lineMarker` projects text through text-region} after selection. It never limits the content searched or paginates match occurrences. Without a marker, READ returns each selected resource's complete readable content. A miss is 204 before projection; an invalid text region is 416.
1220
- - Semantic READ uses a leading decimal as its optional similarity threshold. The remaining one, two, or four integers are the text projection. Without a leading decimal, semantic selection uses the configured default and every integer component belongs to READ projection. Direct FIND instead applies remaining integers to ranked result positions; only a markerless semantic FIND uses the configured default top-K ({§find-semantic-default-top-k}).
1244
+ - §read-selection-projection READ applies `lineMarker` as text coordinates to one
1245
+ exact target underread-exact-target}. Markerless READ synthesizes
1246
+ `<1,16>`; `<1,-1>` explicitly selects all text. Successful positional reads
1247
+ carry the compact requested/returned extent and available total
1248
+ ({§range-extent}). An invalid text region is 416.
1221
1249
 
1222
1250
  ### §open-fold OPEN / FOLD
1223
1251
 
1224
1252
  AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: null }`.
1225
1253
 
1226
- OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). FOLD collapses a log row to its path; OPEN restores its ordinary packet projection, including any preview bound ({§body-projection}). The canonical full body remains available through READ of the log URI. Non-destructive: rows and bodies persist. On any valid row, applying its current state again or targeting a bodyless row is a successful visibility no-op; malformed targets and nonexistent exact coordinates still fail at their addressing boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1254
+ OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). FOLD collapses a log row to its path; OPEN restores its ordinary packet projection, including any preview bound ({§body-projection}). The canonical full body remains available through READ of the log URI with `<1,-1>`. Non-destructive: rows and bodies persist. On any valid row, applying its current state again or targeting a bodyless row is a successful visibility no-op; malformed targets and nonexistent exact coordinates still fail at their addressing boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1227
1255
 
1228
1256
  ### §jsonplurnk The Log's wire format
1229
1257
 
1230
- The `## Log` section renders as a fenced `jsonplurnk` block - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw HEREDOC (`<<:::TAG ... :::TAG`, TAG = the entry's target/log URI), rendered with universal `N:` line prefixes, never as a JSON-escaped string. The carve-out is localized to `body`, so the strip-parser is trivial: after `"body":`, `<<:::TAG` opens and `:::TAG` at column 0 closes; replacing that block with an escaped string recovers strict JSON through `@plurnk/plurnk-contracts`. The body shape is a strict three-state invariant: `"display":"none","body":""` for no body, `"display":"folded"` with the ordinary projection withheld, and `"display":"open","body":HEREDOC` with it shown. A bounded projection also carries `"overflow":"Body content truncated. Use READ log:///<coordinate>/<op> to view the full body."` whether open or folded. The block is data only - no prose leads the fence. `tokens` is the ruler-weight of the row's ordinary packet body: the room OPEN adds and FOLD saves. A FIND's `itemsTokenTotal` is the ruler-weight of the matched entries themselves: the room READing them takes. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/numbered bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body/display state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1258
+ The `## Log` section renders as a fenced `jsonplurnk` block - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw HEREDOC (`<<:::TAG ... :::TAG`, TAG = the entry's target/log URI), rendered with universal `N:` line prefixes, never as a JSON-escaped string. The carve-out is localized to `body`, so the strip-parser is trivial: after `"body":`, `<<:::TAG` opens and `:::TAG` at column 0 closes; replacing that block with an escaped string recovers strict JSON through `@plurnk/plurnk-contracts`. The body shape is a strict three-state invariant: `"display":"none","body":""` for no body, `"display":"folded"` with the ordinary projection withheld, and `"display":"open","body":HEREDOC` with it shown. A bounded projection also carries `"overflow":"Body content truncated. Full body: <log path>"`, naming the row's exact canonical body without prescribing an unbounded retrieval. The block is data only - no prose leads the fence. `tokens` is the ruler-weight of the row's ordinary packet body: the room OPEN adds and FOLD saves. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page has a different weight. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/numbered bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body/display state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1231
1259
 
1232
1260
  §jsonplurnk-dynamic-fence The opening fence length is **dynamic**: one backtick longer than the longest backtick run in the rendered entries (floor 3). A body can carry arbitrary content — a READ of a doc whose own text opens a column-0 triple-backtick fence — which a fixed opener would let close the block early; a dynamic opener can never be closed by its own body content (CommonMark closes a fence only on a line of at least its own length), independent of the `N:` numbering that incidentally keeps text bodies off column 0.
1233
1261
 
1262
+ ### §retrieval-packet-metadata READ/FIND packet metadata
1263
+
1264
+ The packet projects one actionable owner for each retrieval fact:
1265
+
1266
+ | Result mode | Extent | Result-body evidence | Additional aggregate fact |
1267
+ |---|---|---|---|
1268
+ | line READ | compact `line` range | none | none |
1269
+ | exact-coordinate READ | none | top-level `region` | none |
1270
+ | READ-shaped materialization notice | none | none | generic body `lines` |
1271
+ | catalog/path FIND | compact `resource` range | none | none |
1272
+ | broad matcher FIND | compact `resource` range | per-resource match-location counts | nonzero complete `matchLocationCount` |
1273
+ | exact matcher FIND | compact `matchLocation` range | each row's locator/region | none |
1274
+
1275
+ The compact range is `{ unit, total, requested: [first,last], returned?:
1276
+ [first,last] }` ({§range-extent}); empty results omit `returned`. Transparent
1277
+ coordinates let the model determine whether more material exists and choose
1278
+ its own next request, so packet metadata never prescribes `next`, `complete`,
1279
+ or `all`. FIND range cardinality replaces top-level `items`, `lines`, and
1280
+ `matchingPathCount`; line READ likewise omits the rendered-body `lines` count
1281
+ and its internally resolved whole-line region. Exact READ retains only its
1282
+ region. A failed retrieval's Problem owns its range extension rather than
1283
+ repeating it at top level. Generic `tokens` always weighs the rendered body;
1284
+ generic body `lines` remains available on READ-shaped materialization notices
1285
+ that have no retrieval extent. FIND content weights follow {§jsonplurnk}; body
1286
+ truncation remains the independent addressable `overflow` contract.
1287
+
1234
1288
  ### §model-entry The model's own emission, mirrored back
1235
1289
 
1236
- §model-entry-log-curation A `model` log row is the model's **verbatim admitted emission**, mirrored back so it can inspect and curate its own behavior. Actionless, like an `op='error'` row ({§operation-results}): no target, no op executed; `tx` is empty and the emission lives in `rx.content`, typed `text/vnd.plurnk`. **Always born FOLDED** (budget-neutral), line-numbered like all content, and OPEN/FOLD/KILL-able like any log row. Log-KILL clears the `writableBy` gate for the model (the DB-storage curation lever plurnk.md teaches; Log's handler surface — kill only — keeps every other mutating op at 501). The engine writes one after each admitted model turn. Rejected attempts never create model rows.
1290
+ §model-entry-log-curation A model-emission log row is the model's **verbatim emission**, mirrored back so it can inspect and curate its own behavior. It is an actionless artifact: `op` is null, `attrs.kind="model_emission"` identifies the row, no target exists, `tx` is empty, and the emission lives in `rx.content`, typed `text/vnd.plurnk`. Its exact address is the undecorated three-part coordinate `log:///<L>/<T>/<S>` because no operation exists to append. An admitted emission is **always born FOLDED** (budget-neutral), line-numbered like all content, and OPEN/FOLD/KILL-able like any log row. Log-KILL clears the `writableBy` gate for the model (the DB-storage curation lever plurnk.md teaches; Log's handler surface — kill only — keeps every other mutating op at 501). The engine writes one after each admitted model turn. The invalid-emission recovery item under {§emission-admission} mirrors only the latest rejected response, is born FOLDED with `attrs.admission="rejected"`, and is projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
1237
1291
 
1238
1292
  - §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with `READ(worker:///docs/)`. Rendered row paths append `/OP` as optional self-documentation, not a fourth resource level: `log:///1/2/*` selects the turn's item rows, while `log:///**/READ` may deliberately filter that decoration.
1239
- - §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — OPEN/FOLD/KILL take a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}) exactly as `READ(worker:///docs/)` fans out a folder: `FOLD(log:///1/2)` folds turn 1/2's rows. A **well-formed glob that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. 400 remains for a malformed target only (no coordinate, no glob, no slash).
1240
- - §log-region-tagging **Named region tagging: FOLD applies, OPEN/FIND filter** — the log's write-op is **FOLD**, because EDIT can't reach engine-written rows (the OP×resource matrix): `FOLD[tag](region)` folds the region AND stamps the tag on it, additively ({§edit-tags-additive}), via `log_tags` (CASCADE-erased with the row on KILL). The read-ops filter: `OPEN[tag]` and `FIND[tag]` select rows carrying EVERY listed tag ({§find-tag-filter-and-semantics}) — a **targetless** `OPEN[tag]` recalls the whole tagged working-set across the worker, a scoped one filters within its glob; an unknown tag matches nothing (204, no-op success). `[tag]`-applies-on-the-write-op / `[tag]`-filters-on-the-read-ops is the same split entries already use (EDIT vs FIND); FOLD merely stands in for EDIT because the log is not an entry scheme. A fork carries a row's tags with its fold-state ({§machine-processes-fork-copies-the-log}). The model curates named working-sets of its own memory: file-away-under-a-name, recall-by-name.
1293
+ - §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: `FOLD(log:///1/2)` folds turn 1/2's rows. A **well-formed glob that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. 400 remains for a malformed target only (no coordinate, no glob, no slash).
1294
+ - §log-region-tagging **Named region tagging: FOLD applies, OPEN/FIND filter** — the log's write-op is **FOLD**, because EDIT can't reach engine-written rows (the OP×resource matrix): `FOLD[tag](region)` folds the region AND stamps the tag on it, additively ({§edit-tags-additive}), via `log_tags` (CASCADE-erased with the row on KILL). The read-ops filter: `OPEN[tag]` and `FIND[tag]` select rows carrying EVERY listed tag ({§find-tag-filter-and-semantics}) — a **targetless** `OPEN[tag]` recalls the whole tagged working-set across the worker, a scoped one filters within its glob; an unknown OPEN tag is a 204 no-op, while body-less FIND is the ordinary successful empty catalog survey ({§find-result-projection}). `[tag]`-applies-on-the-write-op / `[tag]`-filters-on-the-read-ops is the same split entries already use (EDIT vs FIND); FOLD merely stands in for EDIT because the log is not an entry scheme. A fork carries a row's tags with its fold-state ({§machine-processes-fork-copies-the-log}). The model curates named working-sets of its own memory: file-away-under-a-name, recall-by-name.
1241
1295
  - §log-curation-set-selection **Set selection, never positional curation** — target/glob, optional body matcher, and (for OPEN) tag filters compose into the affected row set. FOLD's tags apply after selection. OPEN and FOLD have no `<L>` marker and never paginate that set; FIND owns result pagination.
1242
1296
 
1243
- The worker's **first** model row is exceptional: a born-OPEN turn-0 **exemplar** — a minimal worked example (`PLAN` → environment `FIND`s → `SEND[102]`) the model always opens on, so the grammar can stay thin (the example teaches the syntax, not a heavy grammar). Its `SEND[102]` names the next action, matching the continuation contract. {§model-entry}
1297
+ The worker's **first** model-emission row is exceptional: a born-OPEN turn-0 **exemplar** — a minimal worked example (`PLAN` → environment `FIND`s → `SEND[102]`) the model always opens on, so the grammar can stay thin (the example teaches the syntax, not a heavy grammar). Its `SEND[102]` names the next action, matching the continuation contract. {§model-entry}
1244
1298
 
1245
- §fold-open-meta-operations **OPEN and FOLD are meta-operations — render directives, not actions.** They change how the world *displays*, never what it *is* (scrolling, not editing). A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). The emission also survives verbatim in the `model` mirror. A **failed** OPEN/FOLD (bad target or matcher) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
1299
+ §fold-open-meta-operations **OPEN and FOLD are meta-operations — render directives, not actions.** They change how the world *displays*, never what it *is* (scrolling, not editing). A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). The emission also survives verbatim in its model-emission mirror. A **failed** OPEN/FOLD (bad target or matcher) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
1246
1300
 
1247
- §kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its emission survives in the `model` mirror. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match ≠ error but a malformed coordinate is) renders like any error.
1301
+ §kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its emission survives in its model-emission mirror. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match ≠ error but a malformed coordinate is) renders like any error.
1248
1302
 
1249
1303
  ### §log-sensitive-request-evidence Durable request evidence
1250
1304
 
@@ -1259,7 +1313,7 @@ secret detection.
1259
1313
  | Query and authored body | Preserved exactly; they are authored content and URI identity, not structurally identifiable credential slots. |
1260
1314
  | Parser failure | Preserves the structural diagnosis and source position without quoting request-metadata contents ({§path-request-metadata}). |
1261
1315
  | Client, fork, packet, and digest | Consume the stored projection; none owns a second redaction policy. |
1262
- | Provider attempt and `model` mirror | `turn_attempts.response` under {§emission-admission} and the folded row under {§model-entry-log-curation} remain exact forensic evidence and are the explicit exception. |
1316
+ | Provider attempt and model-emission mirror | `turn_attempts.response` under {§emission-admission} and the folded row under {§model-entry-log-curation} remain exact forensic evidence and are the explicit exception. |
1263
1317
 
1264
1318
  ### §copy COPY (engine-orchestrated)
1265
1319
 
@@ -1312,42 +1366,56 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
1312
1366
 
1313
1367
  AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal: tags | null, lineMarker? }`.
1314
1368
 
1315
- - §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns retain native shell behavior. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive folder scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax and READ dispatches it directly. This is an explicit plugin contract, never inferred from URL punctuation: new schemes cannot accidentally turn a root resource into unbounded fan-out. For declared folder schemes the same target contract governs FIND and READ - bare = the entry, folder/glob = a scope.
1369
+ - §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns retain native shell behavior. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive FIND scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax. This is an explicit plugin contract, never inferred from URL punctuation.
1316
1370
  - An exact target resolves to the same canonical `(scheme, pathname)` identity
1317
1371
  as READ, entry CRUD, and any preceding `prepareFind()`. URI authorities are
1318
1372
  identity-bearing: `https://example.com/page` queries
1319
1373
  `(https, /example.com/page)`, never `(https, /page)`.
1320
1374
  - §find-glob-filter-on-content `body` matcher operates on entry content (glob/regex/jsonpath/xpath), per `plurnk.md` "Pattern Filtering"; the path-glob lives in the (target), not the body.
1321
- - §find-semantic-default-top-k Every matcher operates only over the candidate set selected by `(target)` and `[tags]`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies the ordinary FIND result scope - never rank the wider corpus and discard out-of-scope hits afterward, which changes ranking meaning and leaks entries across an exact target. A semantic matcher with no `<scope>` returns the configured `PLURNK_SERVICE_SEMANTIC_TOP_K` highest-ranked results. Otherwise integers retain FIND's positional contract: `<N>` selects result N and `<N,M>` selects the inclusive range. A leading decimal first applies a minimum cosine-similarity threshold; following integers select positions within that ranked threshold set. Thus `<0.7,10,20>` means threshold 0.7 followed by results 10 through 20, while positions 1 through K use the ordinary `<1,K>` range. The FIND render budget remains independent of semantic ranking.
1375
+ - §find-semantic-selection Every matcher operates only over the candidate set selected by `(target)` and `[tags]`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies the ordinary FIND result scope. Markerless semantic FIND therefore uses the same `<1,16>` default as every other matcher. Integers retain FIND's positional contract: `<N>` selects result N and `<N,M>` selects the inclusive range. A leading decimal first applies a minimum cosine-similarity threshold; following integers select positions within that ranked threshold set. Thus `<0.7,10,20>` means threshold 0.7 followed by results 10 through 20, while `<0.7>` applies the threshold and the ordinary first-16 page.
1322
1376
  - §find-tag-filter-and-semantics `signal` is a tag filter; entries match if they have ALL listed tags.
1323
1377
  - §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
1324
- - §find-result-catalog-rows Returns
1325
- `FindResult { status, content, mimetype, results, matches, pathnames }`. A
1326
- **body-less** FIND is the **catalog**. Ordinary rows are one per resource:
1378
+ - §find-result-projection **The authored target shape determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsTokenTotal, returnedItemsTokenTotal }`:
1379
+
1380
+ | Target | Matcher body | `range.unit` | Result rows |
1381
+ |---|---|---|---|
1382
+ | exact | absent | `resource` | the one catalog resource |
1383
+ | glob or folder | absent | `resource` | catalog resources |
1384
+ | glob or folder | present | `resource` | matching catalog resources with `matchLocationCount` |
1385
+ | exact | present | `matchLocation` | flat `{ locator?, region? }` locations |
1386
+
1387
+ A glob or folder remains resource mode when it resolves to one path. An exact
1388
+ target remains location mode when it has many locations. A valid exact match
1389
+ with no addressable location is status 200 with `matchingPathCount: 1`,
1390
+ `matchLocationCount: 0`, and no fabricated row; a matcher selecting no
1391
+ resource is 204. A body-less broad empty catalog survey is status 200; an
1392
+ absent exact resource is 404.
1393
+
1394
+ Inside `FindResult`, `matchingPathCount` and `matchLocationCount` describe the
1395
+ complete selection before pagination; the packet curates those facts under
1396
+ {§retrieval-packet-metadata}. `path` is reserved for resource identity; broad results
1397
+ never nest locations, and exact location rows never repeat the resource path.
1398
+ A **body-less** FIND is the **catalog**. Ordinary rows are one per resource:
1327
1399
  `{ path, stream?, tags?, channels: { <uri>: { mimetype, tokens, lines } } }`.
1328
1400
  A terminal single-star path scope is a one-level map: direct entries retain
1329
1401
  that shape, while deeper first-segment directories collapse to
1330
1402
  `{ path: "dir/**", items, tokens }`, where the selector and both aggregates
1331
1403
  describe the exact recursive subtree. Scope summaries are navigation
1332
- metadata, not resources or hidden READ fan-out matches. A matcher FIND
1333
- retains the same one-row-per-resource unit and adds
1334
- `matches: MatchEvidence[]` ({§matcher-selection-signal}). FIND pagination
1335
- counts selected resources, never occurrences. Resource order is rank for
1336
- `~`semantic and candidate order otherwise; evidence retains dialect order
1337
- and exact duplicates deduplicate. `content` is one valid compact JSON array
1338
- with exactly one top-level item per physical line: objects carry no
1339
- pretty-print whitespace, the opening bracket shares the first row, the
1340
- closing bracket shares the last, and only the `N-1` item-boundary newlines
1341
- are added. Universal packet numbering therefore makes result ordinal N
1342
- addressable as line N, matching `<N>` pagination without a second coordinate
1343
- system. Empty and single-item arrays remain one line.
1344
- - §find-count-not-contents **Over the render budget, FIND returns a count, not
1345
- contents** (`PLURNK_SERVICE_FIND_MAX_MATCHES`). A repo-scale recursive
1346
- FIND cannot enumerate safely. When the selected-resource count exceeds the
1347
- budget, `overflow` and `itemsTokenTotal` carry the count and aggregate weight
1348
- while `results`, `matches`, and `pathnames` are empty; no caller may perform
1349
- hidden work from content the model was denied. The gate is independent of
1350
- model window size. `0`/unset disables it.
1404
+ metadata, not resources. Markerless FIND returns positions 1–16 in the
1405
+ selected unit; `<N,M>` selects an inclusive page and `<1,-1>` explicitly
1406
+ selects all. `range` reports the unit, complete result total, normalized
1407
+ request, and returned positions ({§range-extent}). `itemsTokenTotal` weighs the complete matched set while
1408
+ `returnedItemsTokenTotal` weighs the returned resource page; in exact
1409
+ location mode both weigh the one selected resource once. Resource order is
1410
+ rank for `~`semantic and candidate order otherwise; location order is dialect
1411
+ order and exact duplicates deduplicate. The intended drill-down is broad FIND
1412
+ to choose paths, exact-target FIND to choose locations, then exact READ.
1413
+ `content` uses the shared generated-JSON projection
1414
+ ({§json-result-rendering}), so universal packet numbering makes result
1415
+ ordinal N addressable as line N, matching `<N>` pagination without a second
1416
+ coordinate system. Pagination is the only FIND materialization bound; no
1417
+ hidden complete row or location collection is retained behind the public
1418
+ projection.
1351
1419
 
1352
1420
  ### §send SEND
1353
1421
 
@@ -1371,7 +1439,7 @@ AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, signal: nu
1371
1439
  | `terminated_by` | Meaning | Presentation |
1372
1440
  |---|---|---|
1373
1441
  | `NULL` | The model's own terminal or an engine verdict whose exact result already carries the story. An already-drained join is the model's own successful terminal. | No authorship marker. |
1374
- | `cancel` | An external client cancelled the structured scope ({§methods-loop-cancel}). | COLLECT and the termination delta prepend a cancellation marker to the recorded reason, so cancellation cannot masquerade as a deliverable. The model's prior log rows remain untouched. |
1442
+ | `cancel` | An external client cancelled the structured scope ({§methods-loop-cancel}). | COLLECT and the termination delta prepend a cancellation marker to the exact Problem's presentation, so cancellation cannot masquerade as a deliverable. The model's prior log rows remain untouched. |
1375
1443
 
1376
1444
  The engine's failure terminals — **500** (strike threshold) and **508** (cycle), {§engine-rails} — are never the model's to pick; they are the engine ruling the loop failed. The surface is small on purpose: the model says done, waiting, or giving up, and is never asked to hold a correct opinion about *how* it failed or *whether* it can be woken — the engine decides those from state.
1377
1445
 
@@ -1412,9 +1480,10 @@ AST: `{ op: "EXEC", target (optional input source, program, or cwd), body: strin
1412
1480
  canonicalizes `(target)` before effect admission. With no directory override,
1413
1481
  `cwd` is the workspace's `project_root`, where the File scheme writes — never
1414
1482
  the daemon's own cwd. A non-file scheme address is an eligible content source
1415
- only when the registered scheme is a data scheme implementing READ. After
1416
- acceptance, core reparses the complete authored address and resolves one exact,
1417
- unscoped READ through that scheme's ordinary handler and addressed context.
1483
+ only when the registered scheme is a data scheme. After acceptance, core
1484
+ reparses the complete authored address and resolves one exact `<1,-1>` READ
1485
+ through {§universal-read-composition}; internal source consumption never
1486
+ borrows the model-facing 16-line preview.
1418
1487
 
1419
1488
  | Authored target | Body | Canonical effect target | Accepted executor realization |
1420
1489
  | ------------------------------------- | --------- | ----------------------- | ----------------------------------------------------- |
@@ -1487,8 +1556,8 @@ its terminal output surfaces born-OPEN like any close ({§exec-stream}).
1487
1556
  §exec-poll `P` (`mark[1]`) is the **poll cadence**, stored on the subscription.
1488
1557
  While the loop is blocked on a `SEND[202]` wait for that stream, the daemon arms
1489
1558
  a per-worker timer for the tightest open poll cadence and resumes the blocked
1490
- loop every P seconds, floored by `PLURNK_SERVICE_EXEC_WAIT_MS` so it cannot tick
1491
- faster than a turn settles, to inspect progress. It does **nothing while the
1559
+ loop every P seconds, floored by `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS` so it cannot tick
1560
+ faster than the optimistic settlement scale, to inspect progress. It does **nothing while the
1492
1561
  loop is active** because ambient stream deltas already surface progress. An
1493
1562
  open stream without `P` uses exponential backoff
1494
1563
  (`PLURNK_SERVICE_EXEC_POLL_SEC` and `PLURNK_SERVICE_EXEC_POLL_TURNS`); explicit
@@ -1512,9 +1581,29 @@ edge. Stream closure remains a wake edge under every poll policy.
1512
1581
 
1513
1582
  §worker-auto-name **Auto-names are id-free ordinals** — worker names are the addressable authority, so an auto-name is `<prefix>-<N>` (per-workspace monotonic count, the fork `<parent>-fork-<N>` pattern), never a timestamp-hash that would leak machine identity through the hostname. The semantic suffix remains intact; when the complete name would exceed `WORKER_NAME`, generation shortens only the inherited prefix until the predicate admits it. Auto-names never reuse an existing literal and pass through {§worker-name-minting} like explicit names. Name selection and worker creation are one atomic claim: concurrent allocators receive distinct literals, while concurrent ensures of a workspace's default conversation converge on one root worker.
1514
1583
 
1515
- §exec-readpure-ungated A `read` runtime (observes external state, e.g. search) or `pure` runtime (no observable effect, e.g. `:memory:` sqlite) is side-effect-free → **auto-run**: no proposal, no human gate, no notification. Core persists the prepared operation before applying it; that write-ahead staging has no resolution waiter and therefore cannot enter proposal discovery ({§proposal-list}). It skips the gate a host command faces, but it does NOT resolve in-band — like every exec it backgrounds and streams, its output reaching the model through the environment-observation injector (a foisted READ of the stream's new bytes each turn, {§exec-stream}), never a same-turn receipt.
1584
+ §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.
1585
+
1586
+ After all non-SEND operations dispatch, the initiating turn applies {§worker-optimistic-settlement} to only the EXEC streams it started, then dispatches its terminal SEND against the refreshed lifecycle state. An older stream receives no renewed opportunity merely because another turn began. This is a settlement barrier before disposition, not sibling-operation serialization: dependent EXECs remain separate observed turns.
1516
1587
 
1517
- §exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*. Each turn the environment-observation injector reads each owned channel from its byte cursor and publishes the new bytes as an `origin=plurnk` READ at `<runtime>:///<coord>#<channel>`. Streaming deltas are folded; the terminal delta is born OPEN. The row obeys the universal body projection ({§body-projection}): its packet body is bounded and its exact canonical body remains READable through the row's log URI. A stream that closes before a same-turn wait remains pending until this terminal READ crosses the next packet boundary. The EXEC row separately records the command.
1588
+ §exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*.
1589
+ Each turn the environment-observation injector publishes newly publishable content
1590
+ from each owned channel as an `origin=plurnk` READ at
1591
+ `<runtime>:///<coord>#<channel>`, preserving the channel's current mimetype:
1592
+
1593
+ | channel mimetype | while active | at terminal state |
1594
+ |---|---|---|
1595
+ | `text/*` (including `text/stream`) | every new text segment | every remaining segment |
1596
+ | `application/jsonl` or `application/x-ndjson` | complete newline-terminated records | every remaining record |
1597
+ | every other mimetype | nothing | the complete atomic document |
1598
+
1599
+ The per-channel cursor advances only through content actually published, so an
1600
+ active atomic document or trailing partial JSONL record never reaches the model
1601
+ as malformed structured data. Ongoing observations are folded and a terminal
1602
+ observation is born OPEN; a terminal state with no newly publishable body still
1603
+ produces one conclusion row. Every READ then obeys {§body-projection} and
1604
+ therefore renders its selected result complete. A stream that closes before a
1605
+ same-turn wait remains pending until this terminal READ crosses the next packet
1606
+ boundary. The EXEC row separately records the command.
1518
1607
 
1519
1608
  `KILL(<runtime>:///<loop>/<turn>/<seq>)` cancels an active subprocess via
1520
1609
  the subscription registry's stored controller. A terminal stream is immutable:
@@ -1524,8 +1613,8 @@ The runtime scheme participates in the durable lookup; a completed `sh:///`
1524
1613
  stream cannot fall through an internal `exec`-only query. {§stream-control}
1525
1614
 
1526
1615
  §exec-env-scoped **Scoped environment.** An EXEC subprocess inherits the *project's* environment — its `.env`, the standard shell vars — so the model's commands run as the project expects; but never plurnk's own secrets: the provider API keys and `PLURNK_*` config are stripped before the spawn, so a model-executed command can't `printenv` the engine's keys. The service owns the scoping policy (the denylist); the executor spawns with the env it is handed.
1527
- - §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits `EXEC + SEND[102]` as ever; the wake-shaped world simply arrives one packet sooner. Lives at the post-EXEC breath seam in `runLoop`, upstream of `PLURNK_SERVICE_EXEC_WAIT_MS`. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
1528
- - §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry (writeEntry; tags **UNIONED** across writes — a re-seen URL keeps its history of query slugs), then journals ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `tokens` = the content's count, `attrs` carrying the tags plus `kind:"entry_materialized"`. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked byte primitive, accepts a present MIME-rendered response, and lazily tries browser rendering only when that projection is absent {§html-materialization}. A failed acquisition, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype). **No page body ever rides a packet**; the announcement is the folded row's meta (path + tokens + tags), and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
1616
+ - §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits `EXEC + SEND[102]` as ever; the wake-shaped world simply arrives one packet sooner. It extends selected runtimes beyond the ordinary {§worker-optimistic-settlement} cap before the next packet assembles. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
1617
+ - §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry (writeEntry; tags **UNIONED** across writes — a re-seen URL keeps its history of query slugs), then journals ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `tokens` = the content's count, `attrs` carrying the tags plus `kind:"entry_materialized"`. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked WebFetcher and accepts its model-facing body and available source/evidence channels {§html-materialization}. Generic public HTML follows the same origin-Markdown, configured Tavily, and local-projection routes as exact HTTP acquisition. A failed acquisition, body-production failure, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype) and grants no provider authority. **No page body ever rides a packet**; the announcement is the folded row's meta (path + tokens + tags), and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
1529
1618
 
1530
1619
  ### §proposal The proposal lifecycle
1531
1620
 
@@ -1796,7 +1885,7 @@ Node's pre-script env-file form and the executable's post-script form share the
1796
1885
 
1797
1886
  §operator-config-env-defaults **Every package owns its knobs — `.env.defaults` is the standard.** Each package in the daemon's ecosystem — internal or third-party — ships a `.env.defaults` at its package root declaring its own knobs; the file is the package's configuration reference, traveling in the tarball and changing with the code that reads it. At boot the daemon assembles every installed member's file into one floor (membership = the `@plurnk/*` scope or a `plurnk` package.json field, gated by `PLURNK_PLUGINS_TRUSTED_ONLY` with discover()'s exact semantics), applies it set-if-unset under every operator source, and renders the assembled catalog to `~/.plurnk/.env.defaults`. The catalog is machine-owned, regenerated each boot, and never read back as configuration. A key claimed by two packages fails boot naming both. With the reader-declares discipline, each key has one implementation and one defaults owner.
1798
1887
 
1799
- Model selection: separate alias cascade in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` declares; `PLURNK_MODEL=<alias>` selects. Aliases live in `.env`, not `.env.defaults` (operator-specific).
1888
+ Model selection: separate alias cascade in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` declares; `PLURNK_MODEL=<alias>` selects. Optional `PLURNK_MODEL_CHILD=<alias>` selects the default child provider; unset means inherit the spawning loop's provider. Aliases and selections live in `.env`, not `.env.defaults` (operator-specific).
1800
1889
 
1801
1890
  | Var | Default | Purpose |
1802
1891
  |-------------------------------------------------------------|---------|---------|
@@ -1808,22 +1897,22 @@ Model selection: separate alias cascade in `ProviderRegistry` ({§provider-insta
1808
1897
  | `PLURNK_SERVICE_MAX_COMMANDS` | `-1` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. PLAN and the final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
1809
1898
  | §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | `86400000` | ms wall-clock budget for a single core loop: expiry aborts the loop signal mid-flight (a stuck `generate` included) and the loop terminates `504 loop_timeout` — a legible engine terminal, kin to the exec `<T>` reap's 504 ({§exec-timeout}). |
1810
1899
  | `PLURNK_SERVICE_MAX_STRIKES` | `3` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
1811
- | `PLURNK_SERVICE_EMISSION_ATTEMPTS` | `3` | Completed provider responses allowed beneath one engine turn before an untrustworthy model-turn frame terminates the loop. Bounded interior operation errors are admitted and do not spend this budget. Independent of strikes. |
1900
+ | `PLURNK_SERVICE_EMISSION_ATTEMPTS` | `3` | Completed provider responses allowed beneath one engine turn before an untrustworthy model-turn frame exhausts admission. Bounded interior operation errors are admitted and do not spend this budget. Consecutive exhaustion after the one informed recovery turn terminates independently of strikes. |
1812
1901
  | `PLURNK_SERVICE_PREVIEW_LINES` | `16` | Maximum lines in an ordinary bounded log-body projection ({§body-projection}). |
1813
- | `PLURNK_SERVICE_PREVIEW_CHARS` | `1280` | Maximum characters in an ordinary bounded log-body projection; independently contains single-line bodies ({§body-projection}). |
1902
+ | `PLURNK_SERVICE_PREVIEW_CHARS` | `2560` | Maximum characters in an ordinary bounded log-body projection; independently contains single-line bodies ({§body-projection}). |
1814
1903
  | `PLURNK_SERVICE_MIN_CYCLES` | `3` | Min repetitions before cycle detection fires ({§engine-rails}). |
1815
1904
  | `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | `4` | Max period length cycle detection examines ({§engine-rails}). |
1816
1905
  | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
1817
1906
  | `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | `32768` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
1818
1907
  | `PLURNK_SERVICE_MD_<ALIAS>` | (unset) | Operator reference doc: materializes `<path>` as `worker://plurnk/<ALIAS>.md`, auto-READ into every model worker's turn 0 ({§actor-boundary-doc-injection}). `~` expands to home. |
1819
- | `PLURNK_SERVICE_FILES_ITEMS` | `-1` | Turn-0 catalog preview. Folder-capable schemes render a complete one-level `*` map with `dir/**` rollups; kernel docs remain recursive. `-1` = complete maps; positive `N` caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
1908
+ | `PLURNK_SERVICE_FILES_ITEMS` | `-1` | Turn-0 catalog preview. Folder-capable schemes render a one-level `*` map with `dir/**` rollups; kernel docs remain recursive and explicitly complete. `-1` = markerless first pages; positive `N` explicitly caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
1820
1909
  | `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | (empty — waits indefinitely) | Finite positive milliseconds before cancellation with outcome `timeout`; empty waits, and every other explicit value fails ({§proposal-timeout-cancels}). |
1821
1910
 
1822
1911
  Every core knob listed is enforced at its owning read site; `.env.defaults` is the authoritative default ({§operator-config-env-defaults}). Provider, scheme, executor, mimetype, and client-interface knobs are documented by their owning packages and appear in the assembled catalog.
1823
1912
 
1824
1913
  **Two override semantics — ceiling vs default.** Which kind a var is determines what "override" means across the cascade:
1825
1914
  - **Ceiling** (most-restrictive-wins) — an operator-set hard bound nothing downstream may exceed: not a lower-precedence file, not a per-workspace constraint, not a per-call seam argument. `PLURNK_SERVICE_GIT_ALLOWED` ({§operator-config-git-ceiling}), `PLURNK_SERVICE_MAX_COMMANDS`, `PLURNK_SERVICE_MAX_STRIKES`, and `PLURNK_SERVICE_MAX_TURNS` (`-1` ships it off; a positive value caps the per-call request). The sandbox/cost guarantee: the operator caps it; no client widens it.
1826
- - **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({alias})` request overrides it), `PLURNK_SERVICE_REQUIREMENTS` (the per-call requirements default), and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
1915
+ - **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({alias})` request overrides it) and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
1827
1916
 
1828
1917
  §operator-config-shipped-defaults **The shipped `.env.defaults` is itself under
1829
1918
  test.** It has no active `PLURNK_SERVICE_MD_*` doc alias because policy is a
@@ -1890,7 +1979,7 @@ The composition families remain distinct so one setting's semantics never
1890
1979
  leak into another.
1891
1980
 
1892
1981
  *Defaults — explicit-wins (the client replaces/merges freely):*
1893
- - §operator-config-workspace-files-items `settings.filesItems` (number) **replaces** `PLURNK_SERVICE_FILES_ITEMS` for the workspace: a one-shot opens clean (`0`, no preview), a workspace full (`-1`), or with the file list capped (`N`, memory still full). A single scalar — the client value wins outright.
1982
+ - §operator-config-workspace-files-items `settings.filesItems` (number) **replaces** `PLURNK_SERVICE_FILES_ITEMS` for the workspace: a one-shot opens clean (`0`, no preview), with ordinary markerless pages (`-1`), or with the file list explicitly capped (`N`, other surveys remain markerless). A single scalar — the client value wins outright.
1894
1983
  - §operator-config-workspace-md-docs `settings.mdDocs` (`[{alias, content}]`) **unions** with the server's `PLURNK_SERVICE_MD_*` docs, keyed by alias — a client adds its own repo docs atop the operator's systemwide policy doc. On alias collision the client wins before I/O (a deliberate shadow), so the unselected operator path is not read; every selected non-empty operator path is required, and absence or another read failure rejects materialization with its cause. The client sends content (it owns the file), not a path.
1895
1984
 
1896
1985
  *Ceilings — most-restrictive-wins (the client may only narrow, never widen):*
@@ -1968,7 +2057,7 @@ Its function names are transport-neutral library calls, not public wire names.
1968
2057
  | §methods-event-subscribe Events | `subscribeToEvents(handler) -> unsubscribe` | Subscribes to the raw event source in {§notifications}. A subscriber failure is logged and cannot re-enter engine control flow. |
1969
2058
  | §proposal-list Proposals | `pendingProposals(workspaceId)` | Intersects durable proposed rows with the lifecycle owner's live resolution waiters, then returns their validated {§proposal-projection}; persistence alone cannot advertise an unresolvable client interrupt. |
1970
2059
  | §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution)` | Validates and delivers one accept, reject, or cancel decision to the engine. An unknown or already-resolved id fails; the client protocol owns how the decision arrived. |
1971
- | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, maxTurns?, flags?, openPaths?, alias?, model? })` | Validates a model worker and provider selection, persists the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
2060
+ | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, maxTurns?, flags?, openPaths?, alias?, model?, childAlias?, childModel? })` | Validates a model worker and provider policy, persists it with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
1972
2061
  | §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)` | Begins durable structured cancellation of the worker tree and reaps its process-local scopes. The boolean reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. |
1973
2062
  | §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, statements })` | Dispatches already-parsed grammar statements as one client action and one journal segment. Every statement is an ordered turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep that promise and segment open until resolution. Core exposes no per-op method family. |
1974
2063
  | Client observation | `look({ workspaceId, workerId, statement })` | Runs an already-parsed READ through the full resolver without a log row. A non-READ statement is rejected ({§op-look}). |
@@ -2041,6 +2130,16 @@ loop with a conflicting selection fails before work is accepted. Provider
2041
2130
  instances are cached; no resume path substitutes a boot default for missing or
2042
2131
  malformed durable selection.
2043
2132
 
2133
+ §methods-loop-run-child-provider **Child-provider selection is a durable spawn
2134
+ policy.** Optional `childModel` (client-resolved `<provider>/<model>`, wins) or
2135
+ `childAlias` selects the provider for every WORK/FORK descendant; omitted uses
2136
+ `PLURNK_MODEL_CHILD`, while explicit `childAlias: null` means inherit. Core
2137
+ persists the resolved policy on each loop. A child runs on that provider and
2138
+ carries the same policy deeper; inherit uses the spawning loop's provider and
2139
+ remains inherit. Packet admission is unchanged: a smaller WORK is valid when
2140
+ its packet fits, and an oversized inherited FORK terminates through the ordinary
2141
+ child-loop result without preflight assembly or provider fallback.
2142
+
2044
2143
  §methods-log-coordinate **Log coordinate.** Every `LogEntry` returned by
2045
2144
  `readLog` or emitted through `log/entry` carries `loop_seq` and `turn_seq`
2046
2145
  beside database ids, so a client can render and resolve the logical `L/T/S`
@@ -2063,11 +2162,11 @@ active lifecycle behind.
2063
2162
  |--------------------------------------------------------------|---------|------------|
2064
2163
  | §notifications-log-entry-notify `log/entry` | `{ entry: LogEntry }` | A `log_entries` row is committed. |
2065
2164
  | §notifications-loop-terminated `loop/terminated` | `{ workerId, loopId, result, hitMaxTurns, turnIds, usage, attributions }` | One loop reaches a terminal state. `result` is the exact universal operation result, including its RFC 9457 Problem Details on failure. `attributions` is the sorted union of exact provider-request evidence ({§attribution}), separate from `usage`. Worker and loop are an inseparable owning coordinate. |
2066
- | `loop/proposal` | contracts-owned `ProposalProjection` | Dispatch pauses on a durable 202 proposal. `disposition` is the sole authority for whether a client presents review UI; live and reconnect share {§proposal-projection}. |
2067
- | `workspace/created` | `{ id, name, projectRoot }` | A workspace is created. This is the only current global event. |
2068
- | `workspace/branch-batch` | Branch-batch lifecycle payload | A branch batch enters queued, running, completed, failed, or recovery-required state. |
2069
- | §notifications-stream-event-on-channel-change `stream/event` | `{ entryId, target, channel, state, contentLength, mimetype?, loop_seq?, turn_seq?, sequence? }` | Channel content grows or channel state transitions. `target` is the canonical entry URI; the optional coordinate is copied from schemes whose addresses carry one. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic plugin notification capability does not require it. It carries metadata, not content; consumers use `readEntry` for bytes. |
2070
- | §notifications-stream-concluded `stream/concluded` | `{ entryId, target, subscriptionId, scheme, result, summary, wakeAction, wakeLoopId?, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `target` is the canonical entry URI; the optional coordinate is copied from schemes whose addresses carry one, so clients never parse it back out of `target`. Exact result truth is preserved; `wakeAction` records whether core resumed a parked loop, folded into an active loop, skipped an aborted/cancelled worker, or found no loop. |
2165
+ | §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}. |
2166
+ | §notifications-workspace-created `workspace/created` | `{ id, name, projectRoot }` | A workspace is created. This is the only current global event. |
2167
+ | §notifications-workspace-branch-batch `workspace/branch-batch` | Branch-batch lifecycle payload | A branch batch enters queued, running, completed, failed, or recovery-required state. |
2168
+ | §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. |
2169
+ | §notifications-stream-concluded `stream/concluded` | `{ entryId, workerId, target, subscriptionId, scheme, result, summary, wakeAction, wakeLoopId?, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `workerId` identifies the entry owner; `target` is its canonical URI. The optional coordinate is copied from schemes whose addresses carry one, so clients never parse it back out of `target`. Exact result truth is preserved; `wakeAction` records whether core resumed a parked loop, folded into an active loop, skipped an aborted/cancelled worker, or found no loop. |
2071
2170
  | §notifications-notice-event `notice/event` | `{ loopId, notice: Notice }` | A transient observation or progress notice occurs. It cannot alter durable history, scheduling, recovery, or model-visible failure truth. |
2072
2171
 
2073
2172
  §notifications-stream-event-failure-isolation The plugin-facing
@@ -2150,16 +2249,14 @@ Conditional absence never reorders the surviving default sections.
2150
2249
  | 13 | user | `git` | Per-turn workspace status; empty content is omitted. |
2151
2250
  | 14 | user | `budget` | Model-facing packet pressure; omitted when capacity is unknown. |
2152
2251
  | 15 | user | `prompt` | Current prompt-entry pointers. |
2153
- | 16 | user | `requirements` | Syntax recap deliberately nearest generation. |
2154
2252
 
2155
2253
  The order favors prefix-cache locality where semantics permit: the definition
2156
2254
  leads capability and privileged policy, while the append-mostly log leads the
2157
2255
  volatile user-status clump. It does **not** claim that every system byte is
2158
2256
  immutable or that the complete packet is globally monotone in volatility:
2159
- capabilities, operator notes, and policies can change, and the stable recap is
2160
- deliberately last for model recency. Trust is a separate admission rule. The
2161
- system slot contains trusted control-plane material; attacker-reachable content
2162
- stays in the user slot.
2257
+ capabilities, operator notes, and policies can change. Trust is a separate
2258
+ admission rule. The system slot contains trusted control-plane material;
2259
+ attacker-reachable content stays in the user slot.
2163
2260
 
2164
2261
  #### §packet-plugin-transform Trusted whole-list extension seam
2165
2262
 
@@ -2222,7 +2319,7 @@ the loop-total usage fields remain billing evidence, not gauge inputs.
2222
2319
  - §tokenomics-agnostic-ruler **One model-agnostic ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. The complete model-facing ledger therefore uses `rulerCount = ceil(chars/2)`: one content has one number regardless of which model reads it, with no per-model workspace state or recount pass. Under-policy packets rely on that ruler. Only an over-policy packet being considered for a recovery turn invokes the shipping provider's request-shaped physical measurement.
2223
2320
  - §tokenomics-neutral-telemetry **Budget telemetry is state, not instruction.** The model-facing Budget is exactly one line: token ceiling, current usage and percentage, and free tokens. Per-entry weights remain on log rows where they describe the entries themselves. Packet-level composition, rankings, and visualizations are absent because their salience can redirect the model toward context gardening. OPEN/FOLD/KILL remain documented capabilities; recovery directs the model only after overflow. The model receives enough state to own its context decisions without a competing dashboard.
2224
2321
  - §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as a stable per-content identity. `tokens` is stored in ruler units beside that content and is never keyed or recomputed by model.
2225
- - §tokenomics-provider-usage **Provider usage is transport and cost evidence, not curation state.** Every provider attempt preserves its validated `{§provider-cost}` evidence beside provider-reported prompt, completion, reasoning, and cached quantities. Turns and loops retain the ordered evidence. Their numeric USD projection is `null` if any included cost is unknown; free contributes zero, but unknown never does. Exact decimal evidence remains authoritative over the aggregate floating-point projection. Reasoning and completion are outputs the model cannot FOLD, so they never alter the model-facing Budget ledger.
2322
+ - §tokenomics-provider-usage **Provider usage is transport and cost evidence, not curation state.** Every issued provider operation has durable pre-I/O identity and closes as response or error. Response attempts preserve provider-reported prompt, completion, reasoning, and cached quantities beside validated `{§provider-cost}` evidence; response-less errors preserve zero usage and unknown cost. Attempt rows own this evidence, rejected responses remain included, and the baseline materializes their ordered turn aggregate. `loop/terminated.usage` reports all four loop totals. Direct response cost wins; otherwise exact response usage is priced only by Models.dev. `costUsd` includes authoritative, estimated, and explicitly free attempts and is `null` if any attempt is unknown. Exact decimal evidence remains authoritative over aggregate floating-point projections. Reasoning and completion are outputs the model cannot FOLD, so they never alter the model-facing Budget ledger.
2226
2323
  - §tokenomics-over-budget-floor **The delivered packet is never over budget.** The readout shows the state of the packet the model actually has, and the grinder ({§grinder}) folds the newest turn boundary of an over-ceiling packet before it is sent. A delivered budget headline therefore always has usage <= ceiling, percent <= 100, and free >= 0. The percent describes the post-fold packet. If that one deterministic boundary fold cannot make the packet fit, the recovery/hard-413 contract applies; the engine never reaches backward and chooses older history to hide. The stored failure record renders an overshoot honestly - free floors at zero and percent may exceed 100 - but that record is never sent as an over-budget reasoning surface.
2227
2324
 
2228
2325
  ### §membership Workspace identity, membership, disk co-location
@@ -2266,13 +2363,13 @@ media type, and projection identity remain explicit auxiliary evidence. A
2266
2363
  normal
2267
2364
  `READ(https://host/path?query)` therefore publishes only the sanitized body
2268
2365
  under that exact URL—never raw HTML, response headers, or a channel-selection
2269
- lesson. FIND, matcher READ, and embeddings consume the same stored readable
2366
+ lesson. FIND and embeddings consume the same stored readable
2270
2367
  projection and never re-fetch each match. Because the search family is in
2271
2368
  `PLURNK_SERVICE_EXEC_HOLD`, the cycle holds until acquisition concludes
2272
2369
  ({§exec-hold-until-concluded}), so the next packet contains final
2273
2370
  materialization verdicts and folded ambient rows for every acquired page.
2274
2371
 
2275
- §search-gate Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin search→materialize→FIND/matcher READ and persistence/publication separation. Model web demos run the live composition end to end — real SearXNG, real pages; stubbed acquisition is confined to unit and integration seams and never appears in a demo. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page. Live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions. **The search gates** are rail-family accounting — in-memory per-loop state cleaned at the same seam as strikes, restart-drop accepted (a post-restart duplicate re-fetches; the TTL makes it cheap): an IDENTICAL duplicate (same runtime + command in one loop) **strikes and serves** — status 409 (the strike rail counts the turn failure) carrying the prior ranked digest re-read live from the original exec entry, no re-fetch, no provenance prose; the per-turn CAP (`PLURNK_SERVICE_SEARCH_MAX_PER_TURN`) is flood control — 429 with a legible steer, nothing served.
2372
+ §search-gate Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin search→materialize→FIND and persistence/publication separation. Model web demos run the live composition end to end — real SearXNG, real pages; stubbed acquisition is confined to unit and integration seams and never appears in a demo. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page. Live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions. **The search gates** are rail-family accounting — in-memory per-loop state cleaned at the same seam as strikes, restart-drop accepted (a post-restart duplicate re-fetches; the TTL makes it cheap): an IDENTICAL duplicate (same runtime + command in one loop) **strikes and serves** — status 409 (the strike rail counts the turn failure) carrying the prior ranked digest re-read live from the original exec entry, no re-fetch, no provenance prose; the per-turn CAP (`PLURNK_SERVICE_SEARCH_MAX_PER_TURN`) is flood control — 429 with a legible steer, nothing served.
2276
2373
 
2277
2374
  **Git is the substrate and the repository is the boundary:**
2278
2375
 
@@ -2318,7 +2415,7 @@ identity, and terminal disposition without exposing raw bytes or a base64 lane.
2318
2415
  | Binary with readable projection | Derived Unicode as `text/markdown` | READ uses the projection; source-aware EDIT remains 415. |
2319
2416
  | Binary without projection/over cap | Empty marker under the source binary mimetype | READ and EDIT return 415; private metadata distinguishes unavailable from limit. |
2320
2417
 
2321
- §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ body, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A resource attaches the immutable artifact only after it is complete; identical entry and log bodies therefore share one FTS row, one symbol graph, and one vector set without copying. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every pending resource attaches a terminal classified artifact, identical at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
2418
+ §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ body, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A resource attaches the immutable artifact only after it is complete; identical entry and log bodies therefore share one FTS row, one symbol graph, and one vector set without copying. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every resource completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
2322
2419
 
2323
2420
  Every completed artifact records one terminal disposition: `vector`, `lexical`
2324
2421
  (only no embedder or an operator size ceiling), `excluded` (the configured
@@ -2338,7 +2435,7 @@ Lossless chunk admission requires either the embedder's own counter or an exact
2338
2435
 
2339
2436
  §semantic-max-embed-size **Embedding has an optional size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is an operator-set maximum UTF-8 byte size eligible for vectors; `0` is unlimited and is the shipped default. The measured value is the exact default body READ exposes and the embedder receives. Exhaustive embedding therefore remains the normal posture. When a nonzero ceiling rejects an oversized body, the entry remains directly readable with full graph and lexical indexing; only vectors are absent. The setting is folded into the deep derivation signature, so changing it honestly re-derives affected entries. Client notices report compact aggregate progress; the digest records every non-vector pathname, terminal disposition, and reason for forensic inspection.
2340
2437
 
2341
- §membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature is a stat-only no-op. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection}.
2438
+ §membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature is a stat-only no-op. The version token is either the observed `mtime:size` or the explicit `absent` state; an observed deletion removes the stale readable channels, and a later reappearance is therefore a new divergence rather than a first-sight materialization. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection}.
2342
2439
 
2343
2440
  §membership-emi-divergence-signal **EMI divergence signal.** The detector that gates the work *is* the one that fires this — one mechanism, not a second full read. When the change-detect finds a member moved out-of-band, the delta detector ({§env-delta}) surfaces it as a system `EDIT` log row naming the file, `source="file"` — the model sees what changed without diffing the manifest against memory. The model's own edits are write-through (the entry equals disk after a File write), so the scan never mis-attributes them as external divergence.
2344
2441
 
@@ -2352,7 +2449,9 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
2352
2449
 
2353
2450
  **Rationale.** Workspace is the right scope unit and the containing Git repository is its ordinary development boundary. Membership curation is tiered: Git bounds it by tracking, the client supersedes by overlay, and the model curates its render by READ/FOLD. Supporting several independent repositories as one world would require Plurnk-owned topology, synchronization, and model teaching that Git already solves cleanly by treating them as separate workspaces.
2354
2451
 
2355
- **Schema.** The version-1 baseline stores provider attempts beneath turns.
2452
+ **Schema.** The version-1 baseline stores provider attempts beneath turns; its
2453
+ constraints distinguish pending calls, response evidence, and response-less
2454
+ errors while monetary classification remains explicit.
2356
2455
 
2357
2456
  ### §grinder Budget enforcement: the grinder
2358
2457
 
@@ -2375,9 +2474,9 @@ flowchart TD
2375
2474
  physical -->|no| stop["413 hard stop<br/>no provider call"]
2376
2475
  physical -->|yes| grant{"Recovery grant unused?"}
2377
2476
  grant -->|no| stop
2378
- grant -->|yes| steer["Record recovery Problem<br/>allow PLAN / FOLD / KILL / SEND<br/>rebuild"]
2477
+ grant -->|yes| steer["Record recovery Problem<br/>preserve the ordinary operation contract<br/>rebuild"]
2379
2478
  steer --> finalPhysical{"Final packet physically sendable?"}
2380
- finalPhysical -->|yes| recovery["One constrained<br/>provider call"]
2479
+ finalPhysical -->|yes| recovery["One informed<br/>provider call"]
2381
2480
  finalPhysical -->|no| stop
2382
2481
  ```
2383
2482
 
@@ -2390,12 +2489,12 @@ speculatively or "helpfully."
2390
2489
 
2391
2490
  - §grinder-layer1-rollback **One rule, every turn: fold only the newest boundary.** The model owns context visibility. The grinder makes no relevance judgment and never reaches backward into older history. On overflow it folds, in one set operation, the still-open rows of the newest turn boundary: the immediately prior turn's emissions and the current turn's pre-model rows (foists and wake surfaces; every current-turn row at grind time is engine-written). Turn 1 follows the same rule: no prior turn exists, so its foists are the newest material. The same atomic set operation additively applies the `overflow` tag to every row it folds, so `OPEN[overflow]` can recall automatic curation through the ordinary log contract. Rows and bodies persist and remain re-OPENable.
2392
2491
  - §grinder-errors-exempt **Errors, the prompt, AND the plan are exempt.** The grinder never folds an `op='error'` row (for example budget overflow or another engine rail): errors are the model's durable, curatable record of what went wrong. Nor does it fold the actionless **user prompt** row (`prompt:///<loop>/<N>`): the task frame is not ordinary model-authored memory. Nor a **PLAN row**: the checklist is the model's orientation surface when the grinder fires. All three stay OPEN until the model itself FOLDs or KILLs them.
2393
- - §grinder-hard-413-recovery **The hard overflow is a recovery turn first.** When the packet remains over the policy ceiling but the final recovery request has exact or proven-bounded evidence within the provider's physical window, it is sent once with exact `usage`, `ceiling`, and `deficit` measurements from overflow detection. The recovery turn physically admits only `PLAN`, `FOLD`, `KILL`, and `SEND`; every other authored op resolves 409 without executing. Its Problem directs the model to curate context by FOLDing or KILLing irrelevant log items without selecting those items for it. A next fitting turn clears the recovery state, and a later independent overflow can earn a new recovery. A recovery turn that concludes is a legitimate 200. The boundary is exactly 100% of the policy budget; provider decode capacity is reserved separately. The physical check applies after every row and section in the sent packet exists; only that final admission consumes the one recovery grant.
2394
- - §grinder-hard-413-abort **Hard stop.** A physically unsendable packet, or a second consecutive hard overflow after the constrained recovery turn, abandons the loop at **413 Content Too Large**. Its sibling engine-imposed terminals are HTTP-precise too: `maxTurns` -> 429 and a strike-out -> 500 (508 when cycle-driven). No catch-all 499 and no further passes.
2492
+ - §grinder-hard-413-recovery **The hard overflow is a recovery turn first.** When the packet remains over the policy ceiling but the final recovery request has exact or proven-bounded evidence within the provider's physical window, it is sent once with exact `usage`, `ceiling`, and `deficit` measurements from overflow detection. The Problem names useful recovery options—curate irrelevant history or narrow retrieval—without changing the ordinary operation contract or prescribing an action sequence. A next fitting turn clears the recovery state, and a later independent overflow can earn a new recovery. The boundary is exactly 100% of the policy budget; provider decode capacity is reserved separately. The physical check applies after every row and section in the sent packet exists; only that final admission consumes the one recovery grant.
2493
+ - §grinder-hard-413-abort **Hard stop.** A physically unsendable packet, or a second consecutive hard overflow after the informed recovery turn, abandons the loop at **413 Content Too Large**. Its sibling engine-imposed terminals are HTTP-precise too: `maxTurns` -> 429 and a strike-out -> 500 (508 when cycle-driven). No catch-all 499 and no further passes.
2395
2494
 
2396
- - §tokenomics-fetch-fits-free **A retrieval larger than the available packet room arrives folded.** The result lands in the next build; if that build exceeds the ceiling, the grinder folds the newest boundary, which contains the result. Its row and exact body remain durable and re-OPENable. If the packet still cannot fit, the recovery turn reports exact measurements and the allowed operation set. No ambient packet text prescribes an ordering strategy.
2495
+ - §tokenomics-fetch-fits-free **A retrieval larger than the available packet room arrives folded.** The result lands in the next build; if that build exceeds the ceiling, the grinder folds the newest boundary, which contains the result. Its row and exact body remain durable and re-OPENable. If the packet still cannot fit, the recovery turn reports exact measurements and useful recovery options. No ambient packet text prescribes an ordering strategy.
2397
2496
 
2398
- - §loop-terminals **Engine-imposed terminals are HTTP-precise** — the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND[200]) · `499` model-abandoned (SEND[499], or a cancel) · `429` maxTurns exhausted · `413` budget hard-stop · `500` strike threshold or invalid-emission exhaustion (distinct Problem types; `508` when the crossing strike was a detected cycle) · `504` loop timeout / exec-timeout restamp · `202` the bounded wait — a loop blocked on a live obligation (the model's `SEND[202]<T,P>`, {§wait-obligation-matrix}); a wait on nothing resolves to `200` instead · `100`/`102` queued/running. Never a catch-all, never a new value without an owner schema ruling.
2497
+ - §loop-terminals **Engine-imposed terminals are HTTP-precise** — the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND[200]) · `499` model-abandoned (SEND[499], or a cancel) · `429` maxTurns exhausted · `413` budget hard-stop · `500` strike threshold or invalid-emission exhaustion (distinct Problem types; `508` when the crossing strike was a detected cycle) · `504` loop timeout / exec-timeout restamp · `202` the bounded wait — a loop blocked on a live obligation (the model's `SEND[202]<T,P>`, {§wait-obligation-matrix}); a wait on nothing resolves to `200` instead · `100`/`102` queued/running. Never a catch-all, never a new value without changing the owning schema.
2399
2498
 
2400
2499
  §grinder-strike-coupling **Strike coupling.** A grinder fire bumps the engine's
2401
2500
  per-turn rail verdict, so an overflow contributes one strike under
@@ -2406,7 +2505,7 @@ contributes only one strike and a threshold crossing is classified as 508.
2406
2505
  is no soft exemption. Folded rows still cost their coordinate lines, so
2407
2506
  repeated overflow can legitimately reach the strike threshold.
2408
2507
 
2409
- §grinder-overflow-error-row **What the model sees.** The overflow is an exact RFC 9457 Problem on an `op='error'` log row. Its stable type/title state the broken contract; `detail` and numeric extensions report Token Usage, Token Ceiling, and the positive deficit at the labeled `stage: "overflow-detection"` snapshot. When folding recovered the packet, the Problem also states that resolution and directs the model to keep irrelevant items folded or use smaller retrieval ranges; it never claims that no working room remains after the Budget section has measured a fitting rebuild. A hard recovery occurrence instead carries the enforced `allowedOperations` and its generally valid curation instruction. The packet rebuild that adds either Problem can make the neutral Budget section's current usage larger without contradicting the occurrence snapshot. The Problem is minted before the rebuild, so its derived `log:///<coord>` pointer surfaces in the errors section ({§operation-results}) on that turn. The strike counter stays engine-internal.
2508
+ §grinder-overflow-error-row **What the model sees.** The overflow is an exact RFC 9457 Problem on an `op='error'` log row. Its stable type/title state the broken contract; `detail` and numeric extensions report Token Usage, Token Ceiling, and the positive deficit at the labeled `stage: "overflow-detection"` snapshot. When folding recovered the packet, the Problem also states that resolution and directs the model to keep irrelevant items folded or use smaller retrieval ranges; it never claims that no working room remains after the Budget section has measured a fitting rebuild. A hard recovery occurrence carries concise options for restoring room while leaving the operation grammar unchanged. The packet rebuild that adds either Problem can make the neutral Budget section's current usage larger without contradicting the occurrence snapshot. The Problem is minted before the rebuild, so its derived `log:///<coord>` pointer surfaces in the errors section ({§operation-results}) on that turn. The strike counter stays engine-internal.
2410
2509
 
2411
2510
  The model controls its context; the engine enforces packet physics without
2412
2511
  choosing what older history matters. The same boundary applies on turn 1 and
@@ -2462,7 +2561,7 @@ cross this door, while an ancestry-authorized explicit READ remains available.
2462
2561
  | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
2463
2562
  | §env-delta-sibling-edit Sibling commons mutation | The sibling's successful resolved `EDIT` row and its receipt. | One folded `EDIT` retaining the exact effect and typed attributes. |
2464
2563
  | §env-delta-kernel-entry-edit Kernel-published mutation | The reserved `plurnk` worker's successful resolved `EDIT` row on `worker://plurnk/...`. | One folded `EDIT` retaining the published authority, exact effect, and typed attributes. |
2465
- | §env-delta-filesystem-narration Project-file divergence | The reserved `plurnk` worker records one `source=file` EDIT-shaped event during pre-turn membership reconciliation. | One folded `EDIT` naming the file and carrying the net changed span. No model operation is fabricated as having run. |
2564
+ | §env-delta-filesystem-narration Project-file divergence | The reserved `plurnk` worker records one `source=file` EDIT-shaped event during pre-turn membership reconciliation. | One folded `EDIT` naming the file and carrying the net changed span plus the exact two-coordinate Git porcelain status in `git` metadata when Git reports that path. No model operation is fabricated as having run. |
2466
2565
  | §env-delta-entry-materialization Executor `entry()` sink | The reserved `plurnk` worker records a typed `EDIT` event with `kind="entry_materialized"` and the calling worker as cause. | One folded system `READ` projection advertising newly readable state; the durable event remains an EDIT for replay and forensics ({§exec-entry-sink}). |
2467
2566
 
2468
2567
  §env-delta-attribution **Ownership, authorship, and cause are independent.**
@@ -2662,7 +2761,7 @@ Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualifie
2662
2761
 
2663
2762
  §encrypted-reasoning-carrier **Encrypted reasoning is opaque client evidence.**
2664
2763
  When a provider returns encrypted reasoning items, core attaches that list to
2665
- the admitted model mirror row's `attrs.reasoning`. `log/entry` and `readLog`
2764
+ the admitted model-emission row's `attrs.reasoning`. `log/entry` and `readLog`
2666
2765
  carry it to AG-UI, which may project correlated standard reasoning entities.
2667
2766
  Core never decodes the blobs or renders them into a model packet; readable
2668
2767
  reasoning text remains separate in `assistant.reasoning`. The provider-detail
@@ -2675,13 +2774,13 @@ evidence when a downstream standard cannot represent the complete list.
2675
2774
 
2676
2775
  | row producer | ordinary OPEN projection |
2677
2776
  |---|---|
2678
- | model-origin `READ` or `FIND` | complete result explicitly retrieved by the model |
2777
+ | any `READ` or `FIND` | complete selected operation result |
2679
2778
  | every other nonempty body | head bounded independently by `PLURNK_SERVICE_PREVIEW_LINES` and `PLURNK_SERVICE_PREVIEW_CHARS` |
2680
2779
  | bodyless row | `"display":"none","body":""` |
2681
2780
 
2682
- The exemption is provenance plus operation, not the overloaded operation label: an engine-pushed stream delta shaped as READ remains bounded. Prompts, model mirrors, PLAN/SEND/WORK/FORK bodies, EXEC commands, mutation receipts, ambient deltas, and extension-produced bodies cannot create a second preview policy. A bounded row carries the exact `overflow` message defined by {§jsonplurnk} and names its own `log:///` address. `READ(log:///<coordinate>/<op>)` returns the canonical full body and then applies the authored matcher/range; `FIND(log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores it without bypassing the bound. System/policy sections are not log bodies. Notices are transient non-log observations; they share the line/character bounds but have no durable body or recovery URI.
2781
+ READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. Prompts, model-emission mirrors, PLAN/SEND/WORK/FORK bodies, EXEC commands, mutation receipts, and extension-produced bodies use the bounded projection. A bounded row carries the exact neutral `overflow` message defined by {§jsonplurnk} and names its own `log:///` address. `READ(log:///<coordinate>)`, with the optional self-documenting `/<op>` suffix when one exists, applies its default or explicit text range to the canonical body; `FIND(log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores it without bypassing the bound. System/policy sections are not log bodies. Notices are transient non-log observations; they share the line/character bounds but have no durable body or recovery URI.
2683
2782
 
2684
- §prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt:///<loop>/<N>` as an owner-keyed text/markdown entry, then published to its turn as one actionless lowercase `prompt` log row. No synthetic EDIT or READ operation is invented. The row is born OPEN and obeys {§body-projection}. The **User Prompts** section closes the user-slot status clump as a paths-only list (`* prompt:///<loop>/<N>`), so every frame remains directly READable even after its log row is folded or killed.
2783
+ §prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt:///<loop>/<N>` as an owner-keyed text/markdown entry, then published to its turn as one actionless lowercase `prompt` log row. No synthetic EDIT or READ operation is invented. The row is born OPEN and obeys {§body-projection}. The **Active User Prompts** section closes the user-slot status clump as a paths-only list (`* prompt:///<loop>/<N>`), so every frame remains directly READable even after its log row is folded or killed.
2685
2784
 
2686
2785
  §prompt-self-only The frame is self-only and owner-keyed:
2687
2786
  `entries.owner_id` carries worker identity while the address carries only the
@@ -2701,7 +2800,7 @@ contract.
2701
2800
  §packet-catalog **Catalogs are query results, not packet state.** The packet
2702
2801
  stores no materialized manifest. Complete and one-level entry directories,
2703
2802
  their row shape, and their ordering are ordinary FIND projections owned by
2704
- {§find-result-catalog-rows}; persistent search derivation is a separate index.
2803
+ {§find-result-projection}; persistent search derivation is a separate index.
2705
2804
 
2706
2805
  ### §operation-results Model-facing failures and notices
2707
2806
 
@@ -2779,11 +2878,11 @@ turn.** It cannot execute operations or alter the audited history.
2779
2878
  | Aspect | Contract |
2780
2879
  |-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
2781
2880
  | Scope | One interview for each worker with model-bearing turns; journal-only workers are omitted. |
2782
- | Evidence | The worker's final packet plus every admitted and rejected provider attempt from its history. |
2881
+ | Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. |
2783
2882
  | Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
2784
2883
  | Identity | The worker's durable id is sent as both `workerId` and `primaryWorkerId`, making the synthetic interview its own root without asserting a live worker topology. |
2785
2884
  | Attempts | One call at `PLURNK_SERVICE_REQUIEM_MAX_TOKENS`; only an empty length-limited response receives one retry at `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS`. |
2786
- | Artifacts | `requiem.md` carries testimony and authoritative usage/cost totals; `requiem.json` preserves exact messages, responses, usage, and provider-calculated cost. |
2885
+ | Artifacts | `requiem.md` carries testimony and nullable cost. `requiem.json` is durably materialized before each call and preserves call state, messages, responses, usage, and monetary evidence. |
2787
2886
 
2788
2887
  §turn-lifecycle **Turn-lifecycle liveness.** Provider generation is the long, opaque window in a turn — one or more same-packet emission attempts may occur before the first committed op. A static client screen there is indistinguishable from a hang. The engine brackets the complete attempt window with two `notice/event` notices (`source: "engine:turn"`, `level: "info"`): `turn_awaiting_model` before the first call and `turn_generated` when an emission is accepted or the attempt budget is exhausted. Rejected content never rides the notice channel. Both are suppressed on an aborted loop and broadcast to the workspace like any notice ({§notice-event-notify}).
2789
2888
 
@@ -2791,7 +2890,7 @@ turn.** It cannot execute operations or alter the audited history.
2791
2890
 
2792
2891
  ### §tools user.tools — the capability sheet
2793
2892
 
2794
- §tools-capability-sheet The executable-tools capability sheet renders under `## Registered Executable Tools`, directly after the `definition` (plurnk.md) section and **above** `## Recap`. The heading defines the fenced examples as the closed set of valid executor selectors, not suggestions for an open-ended `[tag]` convention. Optional non-EXEC operations render separately under `## Enabled Optional Operations`, so the executable catalogue remains truthful. Both use `plurnk` fences — one packet, one shape for operation-example sheets — assembled by `PacketBuilder.#collectTools`; a prose notice (e.g. the EXEC-disabled line) stays beside the executor fence, and empty sections are omitted.
2893
+ §tools-capability-sheet The executable-tools capability sheet renders under `## Registered Executable Tools`, directly after the `definition` (plurnk.md) section. The heading defines the fenced examples as the closed set of valid executor selectors, not suggestions for an open-ended `[tag]` convention. Optional non-EXEC operations render separately under `## Enabled Optional Operations`, so the executable catalogue remains truthful. Both use `plurnk` fences — one packet, one shape for operation-example sheets — assembled by `PacketBuilder.#collectTools`; a prose notice (e.g. the EXEC-disabled line) stays beside the executor fence, and empty sections are omitted.
2795
2894
 
2796
2895
  §tools-loop-affinity **The capability sheet describes the current loop.** The
2797
2896
  sheet filters registered capabilities through the same
@@ -2823,25 +2922,27 @@ later boot never refreshes or recreates it.
2823
2922
 
2824
2923
  §schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path one-liner and the latter is the deep pull doc. `SchemeRegistry.teach()` renders the directory, `SchemeRegistry.docs()` resolves corpus-or-manifest documentation, and `docEntries()` materializes the result when core publishes capabilities for a workspace.
2825
2924
 
2826
- ### §requirements The requirements section — static per-turn rules
2827
-
2828
- - §requirements-requirements-render-last Rendered at the end of the user packet
2829
- under `## Recap`, closest to the assistant turn so the contract the model has
2830
- to honor is the most recent text it sees.
2831
- - §requirements-requirements-omitted-when-empty The header is omitted entirely
2832
- when the requirements string is empty.
2925
+ ### §packet-git-status The Git status section — compact repository state
2833
2926
 
2834
- Contains a compact, recency-biased recap of operational law already owned by
2835
- `plurnk.md`: the op shape, one complete turn, and the SEND[200] completion
2836
- condition. This duplication is deliberate; it is the user-slot footer closest
2837
- to generation, not a second contract. PLAN remains mandated by `plurnk.md`
2838
- "Imperatives", so the service injects no additional plan directive.
2927
+ When Git is admitted for the workspace, `## Git Status` reports the current
2928
+ branch, upstream ahead/behind counts, and staged/unstaged/untracked totals. The
2929
+ active direct child of a running branch batch additionally receives its assigned
2930
+ branch and the requirement to commit any project changes and leave the checkout
2931
+ clean before concluding ({§worker-branch-batch-return}); no other worker receives
2932
+ that instruction. The section never repeats an unbounded path list. Per-path state belongs to
2933
+ the durable causal observation: a `source=file` environment-delta row carries
2934
+ the exact two-character porcelain `XY` value as `git` metadata when the status
2935
+ snapshot names that path. The engine takes one snapshot after membership
2936
+ reconciliation and uses it for both projections; no per-file Git process exists.
2839
2937
 
2840
- **Sourcing:** a non-empty `runLoop({ requirements })` / `runTurn({ requirements })` value overrides the default. Otherwise `Paths.defaultRequirements` resolves `PLURNK_SERVICE_REQUIREMENTS` or the required `@plurnk/plurnk-meta/requirements.md` source ({§teaching-corpus}). The engine reads that file for every packet; a failed read fails the build with its cause, and requirements are not persisted or cascaded through the database.
2938
+ ### §requirements Recap footer
2841
2939
 
2842
- **Rationale:** the user's prompt is natural language ("Reply with just the number") and routinely conflicts with the grammar's operational contract. Without an explicit requirement block, the model obeys the prompt literally and never reaches for SEND. Requirements are the contract that wins those conflicts.
2843
-
2844
- ---
2940
+ The user slot ends with `## Recap`, a compact recency-biased reminder of selected
2941
+ operational law already owned by `plurnk.md`. A non-empty `runLoop` / `runTurn`
2942
+ `requirements` value overrides the default; otherwise core reads
2943
+ `PLURNK_SERVICE_REQUIREMENTS` or the required meta-owned `requirements.md` source
2944
+ for every packet. A failed read fails packet assembly with its cause. The footer
2945
+ is one projection path and one authored source, not a second language contract.
2845
2946
 
2846
2947
  ## §matcher Matcher selection and text regions
2847
2948
 
@@ -2902,12 +3003,11 @@ Glob anchoring (`TODO*` starts-with, `*TODO*` contains, `*.log` ends-with,
2902
3003
 
2903
3004
  §matcher-result-resource-selection **A matcher selects resources; it never extracts a value or chooses a retrieval
2904
3005
  window.** Every dialect answers whether a resource matches and may return
2905
- `MatchEvidence { path?, region? }` ({§matcher-selection-signal}). `path` is a
3006
+ `MatchEvidence { locator?, region? }` ({§matcher-selection-signal}). `locator` is a
2906
3007
  canonical structural locator. `region` is a complete `TextRegion` in the exact
2907
3008
  text the model can READ and may be exact or the smallest honest enclosing
2908
- region. A matcher miss is 204. FIND lists a selected resource
2909
- once; READ returns it once, complete unless the authored READ supplied a text
2910
- scope.
3009
+ region. A matcher miss is 204. FIND's target shape projects the selected
3010
+ resources according to {§find-result-projection}.
2911
3011
 
2912
3012
  | Dialect | Selects | Natural use |
2913
3013
  |---|---|---|
@@ -2918,15 +3018,12 @@ scope.
2918
3018
  | `~`semantic `~q` | resources ranked by indexed chunks | chunk text region when available |
2919
3019
  | `@`graph `@<sym` | resources with matching symbol relations | symbol text region when available |
2920
3020
 
2921
- §read-multi-file-fanout **READ uses the FIND contract as a selector, not as a visible intermediate operation.** A READ over a glob, folder, relation matcher, or acquisition-scheme matcher writes one READ log row per selected resource. It does not write a synthetic FIND row. Every matcher delivery carries all of that resource's match evidence. A body-less folder/glob uses the same resource unit. An exact stored-resource content matcher may resolve directly with the same visible contract, preserving content-level outcomes such as the 203 raw-source fallback. A bare body-less entry remains one direct READ. Zero selections write one 204 row. If selection exceeds {§find-count-not-contents}, READ writes one 413 refusal and no hidden deliveries. Fan-out checks cancellation between resources.
2922
-
2923
- **Selection and projection are ordered and independent.** The matcher evaluates
2924
- the complete readable candidate. The READ marker then projects text from each
2925
- selected resource. Match evidence is never an implicit projection: it gives the
2926
- model enough information to author a surgical follow-up READ without the engine
2927
- guessing which occurrence or context window it wants. A locator-only or
2928
- coordinate-less valid result still selects the resource; the service never
2929
- fabricates coordinates. {§read-selection-projection}
3021
+ Match evidence is navigation evidence, never an implicit body projection. The
3022
+ model uses broad FIND to select and page resources, exact FIND to page that
3023
+ resource's locations, then explicit exact READs—parallel in one turn when
3024
+ useful—to retrieve chosen bodies or regions. A locator-only or coordinate-less
3025
+ valid result still selects the resource; the service never fabricates
3026
+ coordinates. {§read-exact-target} {§read-selection-projection}
2930
3027
 
2931
3028
  ### §text-scope-runtime Text-scope runtime projection
2932
3029
 
@@ -2992,7 +3089,7 @@ mutations consume canonical bytes before rendering. A producer may set
2992
3089
  `startLine: null` only when its content is already source-numbered, such as an
2993
3090
  effect receipt.
2994
3091
 
2995
- §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND/model/prompt and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; EXEC and the composed PLAN/SEND/WORK/FORK family use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and universal line numbering. READ/FIND over `log:///` and search consume the complete canonical body instead. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
3092
+ §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, model-emission, prompt, and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; EXEC and the composed PLAN/SEND/WORK/FORK family use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and universal line numbering. READ/FIND over `log:///` and search consume the complete canonical body instead. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
2996
3093
 
2997
3094
  An `EDIT` log row renders its bounded effect receipt (`rx.receipt`) as row
2998
3095
  metadata and join context, not its input statement. Proposal-gated file EDITs
@@ -3023,10 +3120,14 @@ Carried from the contract walk; durable.
3023
3120
  - **Binary markers** → 415 for text operations. A readable binary source is durably represented as projected `text/markdown` under {§membership-source-projection}; source-aware File EDIT remains 415.
3024
3121
  - **EDIT `<L>` on non-existent entry** → body becomes content; `<L>` is positional-only on existing content.
3025
3122
  - §copy-l-source-range **COPY/MOVE source scope** selects only the addressed source channel and
3026
- transfers canonical text without the packet's `N:` prefix. A MOVE removes
3123
+ first resolves and, when required, prepares the same canonical
3124
+ owner-addressed representation as exact READ/FIND. It transfers canonical
3125
+ text without the packet's `N:` prefix. A MOVE removes
3027
3126
  that same selected region; an unscoped MOVE removes only the selected
3028
3127
  channel, deleting the entry only when no channels remain. A binary marker
3029
- is not transferable; a readable binary projection is already a textual channel.
3128
+ is not transferable; a readable binary projection is already a textual
3129
+ channel. A selected producer failure aborts before destination mutation;
3130
+ successful non-`200` content remains transferable.
3030
3131
 
3031
3132
  - **COPY/MOVE destination scope** is independent of the source scope and lowers
3032
3133
  through the destination scheme's `editBatch`.