@plurnk/plurnk-service 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/.env.defaults +21 -12
  2. package/INSTALL.md +11 -7
  3. package/SPEC.md +437 -304
  4. package/dist/build-info.json +1 -1
  5. package/dist/content/edit-collision.d.ts +5 -0
  6. package/dist/content/edit-collision.d.ts.map +1 -0
  7. package/dist/content/edit-collision.js +14 -0
  8. package/dist/content/edit-collision.js.map +1 -0
  9. package/dist/content/edit-receipt.d.ts +3 -2
  10. package/dist/content/edit-receipt.d.ts.map +1 -1
  11. package/dist/content/edit-receipt.js +58 -13
  12. package/dist/content/edit-receipt.js.map +1 -1
  13. package/dist/content/index.d.ts +4 -1
  14. package/dist/content/index.d.ts.map +1 -1
  15. package/dist/content/index.js +3 -1
  16. package/dist/content/index.js.map +1 -1
  17. package/dist/content/line-anchors.d.ts +41 -0
  18. package/dist/content/line-anchors.d.ts.map +1 -0
  19. package/dist/content/line-anchors.js +191 -0
  20. package/dist/content/line-anchors.js.map +1 -0
  21. package/dist/content/read-projector.d.ts +7 -1
  22. package/dist/content/read-projector.d.ts.map +1 -1
  23. package/dist/content/read-projector.js +46 -10
  24. package/dist/content/read-projector.js.map +1 -1
  25. package/dist/content/read-resolve.js +3 -3
  26. package/dist/content/read-resolve.js.map +1 -1
  27. package/dist/core/BudgetReadout.d.ts.map +1 -1
  28. package/dist/core/BudgetReadout.js +9 -2
  29. package/dist/core/BudgetReadout.js.map +1 -1
  30. package/dist/core/ChannelWrite.js +1 -1
  31. package/dist/core/ChannelWrite.js.map +1 -1
  32. package/dist/core/Dispatcher.d.ts +13 -3
  33. package/dist/core/Dispatcher.d.ts.map +1 -1
  34. package/dist/core/Dispatcher.js +391 -113
  35. package/dist/core/Dispatcher.js.map +1 -1
  36. package/dist/core/DurableStatement.d.ts.map +1 -1
  37. package/dist/core/DurableStatement.js +2 -0
  38. package/dist/core/DurableStatement.js.map +1 -1
  39. package/dist/core/Engine.d.ts +13 -14
  40. package/dist/core/Engine.d.ts.map +1 -1
  41. package/dist/core/Engine.js +434 -300
  42. package/dist/core/Engine.js.map +1 -1
  43. package/dist/core/Engine.sql +156 -90
  44. package/dist/core/ExecutableTools.d.ts +10 -0
  45. package/dist/core/ExecutableTools.d.ts.map +1 -0
  46. package/dist/core/ExecutableTools.js +41 -0
  47. package/dist/core/ExecutableTools.js.map +1 -0
  48. package/dist/core/ExecutorRegistry.d.ts +3 -3
  49. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  50. package/dist/core/ExecutorRegistry.js +2 -2
  51. package/dist/core/ExecutorRegistry.js.map +1 -1
  52. package/dist/core/LogBody.d.ts +2 -0
  53. package/dist/core/LogBody.d.ts.map +1 -1
  54. package/dist/core/LogBody.js +17 -5
  55. package/dist/core/LogBody.js.map +1 -1
  56. package/dist/core/LogEntryProjection.d.ts +14 -0
  57. package/dist/core/LogEntryProjection.d.ts.map +1 -0
  58. package/dist/core/LogEntryProjection.js +38 -0
  59. package/dist/core/LogEntryProjection.js.map +1 -0
  60. package/dist/core/ModelCall.d.ts +27 -0
  61. package/dist/core/ModelCall.d.ts.map +1 -0
  62. package/dist/core/ModelCall.js +125 -0
  63. package/dist/core/ModelCall.js.map +1 -0
  64. package/dist/core/PacketBuilder.d.ts +10 -10
  65. package/dist/core/PacketBuilder.d.ts.map +1 -1
  66. package/dist/core/PacketBuilder.js +131 -103
  67. package/dist/core/PacketBuilder.js.map +1 -1
  68. package/dist/core/ProblemLog.d.ts.map +1 -1
  69. package/dist/core/ProblemLog.js +1 -0
  70. package/dist/core/ProblemLog.js.map +1 -1
  71. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  72. package/dist/core/ProposalLifecycle.js +3 -4
  73. package/dist/core/ProposalLifecycle.js.map +1 -1
  74. package/dist/core/ProviderInstantiate.d.ts.map +1 -1
  75. package/dist/core/ProviderInstantiate.js +23 -6
  76. package/dist/core/ProviderInstantiate.js.map +1 -1
  77. package/dist/core/SchemeRegistry.js +7 -7
  78. package/dist/core/SchemeRegistry.js.map +1 -1
  79. package/dist/core/StrikeRail.d.ts +0 -1
  80. package/dist/core/StrikeRail.d.ts.map +1 -1
  81. package/dist/core/StrikeRail.js +6 -4
  82. package/dist/core/StrikeRail.js.map +1 -1
  83. package/dist/core/caps/CapsResolve.js +1 -1
  84. package/dist/core/caps/CapsResolve.js.map +1 -1
  85. package/dist/core/caps/DbEntryCaps.d.ts +2 -1
  86. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
  87. package/dist/core/caps/DbEntryCaps.js +8 -5
  88. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  89. package/dist/core/caps/DbProjectionCaps.d.ts +1 -0
  90. package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
  91. package/dist/core/caps/DbProjectionCaps.js +29 -0
  92. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  93. package/dist/core/caps/SchemeCtxImpl.d.ts +5 -2
  94. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
  95. package/dist/core/caps/SchemeCtxImpl.js +6 -4
  96. package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
  97. package/dist/core/fork.d.ts.map +1 -1
  98. package/dist/core/fork.js +23 -7
  99. package/dist/core/fork.js.map +1 -1
  100. package/dist/core/fork.sql +33 -12
  101. package/dist/core/git-membership.d.ts.map +1 -1
  102. package/dist/core/git-membership.js +1 -2
  103. package/dist/core/git-membership.js.map +1 -1
  104. package/dist/core/git-state.js +1 -1
  105. package/dist/core/git-state.js.map +1 -1
  106. package/dist/core/packet-wire.d.ts +4 -1
  107. package/dist/core/packet-wire.d.ts.map +1 -1
  108. package/dist/core/packet-wire.js +248 -90
  109. package/dist/core/packet-wire.js.map +1 -1
  110. package/dist/core/provider-accounting.d.ts +24 -0
  111. package/dist/core/provider-accounting.d.ts.map +1 -0
  112. package/dist/core/provider-accounting.js +76 -0
  113. package/dist/core/provider-accounting.js.map +1 -0
  114. package/dist/core/search-gate.d.ts +2 -2
  115. package/dist/core/search-gate.d.ts.map +1 -1
  116. package/dist/core/search-gate.js +8 -8
  117. package/dist/core/search-gate.js.map +1 -1
  118. package/dist/core/token-ruler.js +1 -1
  119. package/dist/core/token-ruler.js.map +1 -1
  120. package/dist/core/turn-scheduler.js +1 -1
  121. package/dist/core/turn-scheduler.js.map +1 -1
  122. package/dist/digest/Digest.d.ts.map +1 -1
  123. package/dist/digest/Digest.js +220 -109
  124. package/dist/digest/Digest.js.map +1 -1
  125. package/dist/digest/digest.sql +40 -18
  126. package/dist/schemes/Exec.d.ts.map +1 -1
  127. package/dist/schemes/Exec.js +111 -101
  128. package/dist/schemes/Exec.js.map +1 -1
  129. package/dist/schemes/File.d.ts +5 -4
  130. package/dist/schemes/File.d.ts.map +1 -1
  131. package/dist/schemes/File.js +24 -22
  132. package/dist/schemes/File.js.map +1 -1
  133. package/dist/schemes/Log.d.ts +11 -0
  134. package/dist/schemes/Log.d.ts.map +1 -1
  135. package/dist/schemes/Log.js +171 -106
  136. package/dist/schemes/Log.js.map +1 -1
  137. package/dist/schemes/Log.sql +48 -32
  138. package/dist/schemes/Prompt.d.ts +3 -3
  139. package/dist/schemes/Prompt.d.ts.map +1 -1
  140. package/dist/schemes/Prompt.js +4 -1
  141. package/dist/schemes/Prompt.js.map +1 -1
  142. package/dist/schemes/Skill.d.ts +4 -4
  143. package/dist/schemes/Skill.d.ts.map +1 -1
  144. package/dist/schemes/Skill.js +3 -0
  145. package/dist/schemes/Skill.js.map +1 -1
  146. package/dist/schemes/Worker.d.ts +4 -4
  147. package/dist/schemes/Worker.d.ts.map +1 -1
  148. package/dist/schemes/Worker.js +9 -5
  149. package/dist/schemes/Worker.js.map +1 -1
  150. package/dist/schemes/_entry-crud.d.ts +0 -1
  151. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  152. package/dist/schemes/_entry-crud.js +15 -9
  153. package/dist/schemes/_entry-crud.js.map +1 -1
  154. package/dist/schemes/_entry-crud.sql +2 -14
  155. package/dist/schemes/_entry-find.d.ts +13 -12
  156. package/dist/schemes/_entry-find.d.ts.map +1 -1
  157. package/dist/schemes/_entry-find.js +33 -28
  158. package/dist/schemes/_entry-find.js.map +1 -1
  159. package/dist/schemes/_entry-find.sql +2 -21
  160. package/dist/schemes/_entry-graph.sql +1 -1
  161. package/dist/schemes/_entry-manifest.d.ts +5 -17
  162. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  163. package/dist/schemes/_entry-manifest.js +28 -24
  164. package/dist/schemes/_entry-manifest.js.map +1 -1
  165. package/dist/schemes/_entry-ops.d.ts +5 -4
  166. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  167. package/dist/schemes/_entry-ops.js +87 -47
  168. package/dist/schemes/_entry-ops.js.map +1 -1
  169. package/dist/schemes/_entry-ops.sql +30 -4
  170. package/dist/schemes/_entry-send.js +4 -4
  171. package/dist/schemes/_entry-send.js.map +1 -1
  172. package/dist/schemes/_search-index.d.ts.map +1 -1
  173. package/dist/schemes/_search-index.js +10 -2
  174. package/dist/schemes/_search-index.js.map +1 -1
  175. package/dist/schemes/exec-abort.js +2 -2
  176. package/dist/schemes/exec-abort.js.map +1 -1
  177. package/dist/server/Daemon.d.ts +1 -1
  178. package/dist/server/Daemon.d.ts.map +1 -1
  179. package/dist/server/Daemon.js +25 -23
  180. package/dist/server/Daemon.js.map +1 -1
  181. package/dist/server/drain.sql +2 -2
  182. package/dist/server/envelope.d.ts +0 -2
  183. package/dist/server/envelope.d.ts.map +1 -1
  184. package/dist/server/envelope.js.map +1 -1
  185. package/dist/server/envelope.sql +2 -2
  186. package/dist/server/lifecycle-recovery.sql +25 -15
  187. package/dist/server/logEntry.d.ts +1 -0
  188. package/dist/server/logEntry.d.ts.map +1 -1
  189. package/dist/server/logEntry.js +13 -1
  190. package/dist/server/logEntry.js.map +1 -1
  191. package/dist/server/logEntry.sql +5 -1
  192. package/migrations/001_schema.sql +603 -207
  193. package/package.json +39 -34
  194. package/dist/core/BudgetOverflow.d.ts +0 -20
  195. package/dist/core/BudgetOverflow.d.ts.map +0 -1
  196. package/dist/core/BudgetOverflow.js +0 -49
  197. package/dist/core/BudgetOverflow.js.map +0 -1
  198. package/dist/core/caps/DbTagCaps.d.ts +0 -10
  199. package/dist/core/caps/DbTagCaps.d.ts.map +0 -1
  200. package/dist/core/caps/DbTagCaps.js +0 -46
  201. package/dist/core/caps/DbTagCaps.js.map +0 -1
package/SPEC.md CHANGED
@@ -26,8 +26,9 @@ flowchart LR
26
26
  | **agent** | PLURNK | The plurnk runtime. Acts in-workspace as the reserved `plurnk` worker ({§actor-boundary} self-hosting), never a privileged singleton owning its own entries ({§entry-owner}, {§machine-processes}). |
27
27
  | **workspace** | Core | Durable user-named shared world. Persists across workers and process restarts. Identity: `workspaces.id` + unique `workspaces.name`. |
28
28
  | **worker** | Core | Durable actor and private history over one workspace. Owns its loops and log rows, may carry a `parent_worker_id`, and has one process-local cancellation scope while active. |
29
- | **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 budget-overflow · 429 turn-ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
29
+ | **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 context-envelope rejection · 429 turn-ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
30
30
  | **turn** | Core | One engine scheduling unit (or one client-op scheduling unit). A model turn sends one assembled prompt through one or more emission attempts and admits at most one response. Many turns may belong to one loop. Identity: `(loop_id, sequence)`. |
31
+ | **model call** | Core/provider | One logical `provider.generate` invocation. Emission attempts and BARE inferences share this durable accounting owner; provider retries remain cardinal physical requests beneath it. Identity: `(turn_id, sequence)`. |
31
32
  | **op** | Model/core | One DSL operation the model emits, parsed into a `PlurnkStatement`. One admitted turn produces zero or more ops. |
32
33
  | **statement** | Model/core | A parsed op: the `PlurnkStatement` AST from `@plurnk/plurnk-contracts`. |
33
34
  | **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an actionless `op='error'` row ({§operation-results}). Actionless artifacts carry no fabricated operation. |
@@ -41,7 +42,7 @@ flowchart LR
41
42
 
42
43
  | Term | Meaning |
43
44
  |---|---|
44
- | **entry** | The unit of canonical state. Identity: `(workspace, owner, scheme, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus `tags` and `attributes`. |
45
+ | **entry** | The unit of canonical state. Identity: `(workspace, owner, scheme, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus private `attributes`. |
45
46
  | **channel** | A named content buffer on an entry. Examples: `body`, `stdout`, `stderr`, `headers`, `symbols`. Each channel has `content`, `mimetype`, `tokens`, `state`. |
46
47
  | **scope** | A scheme-manifest declaration ignored by core; registrations are discovered at boot and are not persisted. Entry sharing and privacy are owner-based; #80 owns retiring this residual axis. |
47
48
  | **scheme** | An addressed capability family + handler. Built-ins include `worker`, `prompt`, `log`, and bare/file paths; discovered schemes and executor-runtime tags extend that set. Internal `exec` routes the EXEC op but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
@@ -76,8 +77,7 @@ These are the complete strike sources:
76
77
  | Strike source | Exact trigger | Model-visible occurrence |
77
78
  |---------------------|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
78
79
  | Hard result | An admitted non-`EXEC` operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `501`. | The originating failure row. |
79
- | Grinder | Packet overflow caused a grinder fold or admitted hard-recovery turn ({§grinder-strike-coupling}). | The exact overflow Problem row. |
80
- | Terminal steering | An idle `SEND[102]` or a final disposition refused at 409 sets the turn's steering ruling ({§send}). | The idle rail row or refused SEND row. |
80
+ | Terminal steering | An idle SEND with signal `102` or a final disposition refused at 409 sets the turn's steering ruling ({§send}). | The idle rail row or refused SEND row. |
81
81
  | Cycle | The configured consecutive fingerprint pattern repeats. | None; cycle detection itself is private engine accounting. |
82
82
 
83
83
  `EXEC` results remain exact model-visible evidence but are always soft: an
@@ -98,6 +98,7 @@ shown. The current streak may ride first-party provider metadata
98
98
  | **verdict** | The end-of-turn ruling computed inline in `Engine.runLoop` from the strike rail and independent loop terminals. No filter chain. |
99
99
  | **strike** | One admitted turn matching at least one source above. |
100
100
  | **emission attempt** | One completed provider exchange beneath an engine turn. ANTLR admits it when it has a trustworthy PLAN...SEND frame and no boundary-destroying tail. A hard error bounded to an interior statement becomes a failed operation inside the admitted turn; a rejected attempt is forensic evidence, not another turn or an engine strike. |
101
+ | **BARE inference** | One body-only child-provider model call whose response becomes an ordinary BARE log result. It has no worker, packet, tools, output grammar, or persistent child state ({§bare-inference}). |
101
102
  | **cycle** | A repeated turn fingerprint across consecutive turns. Detection strikes silently under the rule above. |
102
103
  | §mode-ask-read-only **mode** | `"ask" \| "act"`. Per-loop. Ask = read-only: the dispatch gate refuses every side-effecting op (a filesystem write — EDIT/COPY-dest/MOVE/KILL on the `file` scheme — or any EXEC invocation); reads of the workspace stay open. `act` = full surface. Ask never changes the world. |
103
104
  | **flag** | Per-loop value: `mode`, `noWeb`, and `noInteraction` shape scheme authority ({§manifest-flag-affinity}); `auto` and `noProposals` select proposal settlement. |
@@ -231,7 +232,7 @@ preserving the originating failure.
231
232
  flowchart LR
232
233
  actor["Worker A"] -->|"shared file or shared entry op"| state["Shared project files<br/>and shared workspace entries"]
233
234
  state -->|"folded attributed delta<br/>environment door"| log["Worker B log"]
234
- actor -->|"SEND(worker://B)<br/>voice door"| log
235
+ actor -->|"SEND to worker B<br/>voice door"| log
235
236
  client["User / client"] -->|"loop.inject<br/>voice door"| log
236
237
  ```
237
238
 
@@ -253,7 +254,7 @@ file or ancestry-authorized entry through ordinary dispatch ({§worker-read-scop
253
254
  | Door | Carries | Wake behavior |
254
255
  | ----------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
255
256
  | Environment | A change to a shared project file or shared worker entry, as a folded attributed delta. | Ambient state never wakes an idle worker ({§env-delta}). |
256
- | Voice | A directed `loop.inject` or `SEND(worker://name)` message. | An active worker folds it into its next turn; an idle one wakes. |
257
+ | Voice | A directed `loop.inject` or `## SEND0 (worker://name)` message. | An active worker folds it into its next turn; an idle one wakes. |
257
258
 
258
259
  §actor-boundary-no-mutex **Wild west by default; explicit branch batches are the exception.** Ordinary workers share workspace state without locks. Coordination is cooperative and softly fenced (the {§membership} `read-only` overlay, a workspace policy, bounds every worker's writable surface uniformly — {§machine-processes}); a conflict *surfaces* as a delta rather than being prevented. A branch-tagged WORK/FORK opts the whole workspace into the bounded, exclusive Git transaction in {§worker-branch-batch}. It is not a general entry mutex or a hidden per-worker filesystem.
259
260
 
@@ -290,7 +291,9 @@ the `plurnk` worker's log; the model sees the shared entry through its own READ.
290
291
  Client-provided workspace documents union with the operator set at the same
291
292
  entry surface.
292
293
 
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.
294
+ §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS` foists turn-0 FINDs into the worker's first turn, so a worker opens with a navigable map instead of blank. An enabled preview executes exactly four orienting surveys in order: project files (`## FIND0 [+init] (*)`), workspace commons (`## FIND0 [+init] (worker:///*)`), the worker's own space (`## FIND0 [+init] (worker://~/*)`), and kernel docs (`## FIND0 [+init,+docs] (worker://plurnk/docs/**) <1,-1>`). Their log classifications make the opening survey one `init` set while retaining `docs` on its documentation row ({§log-item-tags}). A shallow result renders direct entries normally and every deeper first-segment directory as an actionable `dir/**` summary with its recursive `items` and `tokens`. Ordinary surveys use FIND's markerless first-16 page, whose range metadata reports the requested and returned page against the complete result total; only the small curated kernel-doc surface explicitly selects all. The opening exemplar therefore demonstrates both `*` and `**` without normalizing an all-results override. Every survey executes even when empty because zero results are useful orientation. A positive `N` explicitly caps only the file map's rendered rows, using the map's actual direct-entry-plus-directory count; `-1` enables the ordinary markerless page; unset / `0` disables previews. `log://` is absent because the current worker's log already renders in present mode.
295
+
296
+ §worker-initialization-entry **Worker initialization is not model output.** A worker's first loop begins with one born-OPEN actionless row at `log:///1/1/1`: `origin="plurnk"`, `op` null, and `attrs.kind="initialization"`. Its `text/vnd.plurnk` body dynamically mirrors the turn-zero PLAN, the orienting operations actually dispatched, and terminal `SEND0 [102]`. The PLAN states `* Initialization complete.` and `* Next: address the prompt.`; SEND hands off with `Next, address the prompt.`
294
297
 
295
298
  ### §machine-processes The machine and its processes: workspace, worker, fork
296
299
 
@@ -326,8 +329,8 @@ terminal history.**
326
329
  | Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
327
330
  | Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
328
331
  | Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
329
- | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, tags, fold state, and the matching observation cursor are copied as terminal history. |
330
- | §machine-processes-fork-cost **Turn usage and cost** | Worker | Copied turns carry zero usage and cost; branch totals cover new generation only and workspace spend stays exact. |
332
+ | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, curation effects, tags, fold state, and the matching observation cursor are copied as terminal history. |
333
+ | §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but `model_calls`, emission-admission rows, and physical provider requests are not: one issued call or request has one owning worker. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
331
334
  | Private worker entries (`worker://~/...`) | Worker | Deep-copied with ownership remapped; parent and child then diverge. |
332
335
  | Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
333
336
 
@@ -344,6 +347,14 @@ therefore carries only shared project-file and shared-entry changes
344
347
 
345
348
  §machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `plurnk` (the runtime's self-hosting worker) — set once at creation and inherited by a fork. `listWorkers` returns it, so a client interface identifies actor class without parsing the name, which is set at instantiation and immutable (a worker is permanent history, {§machine-processes-worker-is-its-log}).
346
349
 
350
+ §worker-provider-identity **A worker owns a durable provider identity distinct
351
+ from its database id.** Creation mints a globally unique, opaque 128-bit value;
352
+ forks mint their own value. Core supplies it as the provider `workerId` for every
353
+ emission and supplies the lineage root's value as `primaryWorkerId`
354
+ ({§provider-cache-identity}). Database ids remain the internal relational and
355
+ client coordinate. BARE calls use isolated per-call provider identities rather
356
+ than either worker value.
357
+
347
358
  §worker-primary **The primary worker is the lineage root.** The PRIMARY worker of a turn's lineage is the no-parent root reached by walking `parent_worker_id` up; a no-parent worker is its own primary. Core supplies it on the first-party metadata channel alongside `Worker-Id` (same gate, computed per turn), stamped on EVERY turn including the primary's own (where it equals `Worker-Id`) — absent-with-a-Worker-Id is a contract violation, never a silent "assume primary." An unresolvable root (a corrupt/cyclic parent chain the `parent != id` CHECK forbids) fails hard. Providers emits it as `Plurnk-Worker-Primary`; a consumer routes primary-vs-spawned by equality (`Worker-Primary == Worker-Id` ⇒ the primary; `!=` ⇒ any-depth spawn, no depth math) and groups the worker tree by the shared root.
348
359
 
349
360
  §machine-processes-fork-shares-the-world **A fork copies worker-owned history
@@ -402,9 +413,9 @@ literal `workers.name` value.
402
413
  | `READ` | existing literal name | Collect the named worker's deliverable. |
403
414
  | `KILL` | existing literal name, `~` | Terminate the named worker or caller. |
404
415
 
405
- - §worker-scheme-spawn **Spawn** — `WORK(worker://<name>):task` creates a new worker sister (empty log) and starts it with `task` on its first loop. WORK/FORK are the worker-creation verbs (grammar 0.74.55): EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. A name is **frozen per worker** but **reclaimable across time** ({§machine-processes-worker-origin}): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `worker_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `worker '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error.
406
- - §worker-scheme-irc **irc** — `SEND(worker://<name>):msg` delivers `msg` to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). `SEND(worker://~):msg` targets the caller; a literal name with no worker in the workspace is 404.
407
- - §worker-scheme-fork **Fork** — `FORK(worker://<name>):task` branches the
416
+ - §worker-scheme-spawn **Spawn** — `## WORK0 (worker://<name>)` with a task body creates a new worker sister (empty log) and starts it with that task on its first loop. WORK/FORK are the worker-creation verbs: EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. A name is **frozen per worker** but **reclaimable across time** ({§machine-processes-worker-origin}): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `worker_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `worker '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error.
417
+ - §worker-scheme-irc **irc** — `## SEND0 (worker://<name>)` with a message body delivers it to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). `## SEND0 (worker://~)` targets the caller; a literal name with no worker in the workspace is 404.
418
+ - §worker-scheme-fork **Fork** — `## FORK0 (worker://<name>)` with a task body branches the
408
419
  current worker into a **named** sister: its log is deep-copied
409
420
  ({§machine-processes-fork-copies-the-log}), which continues with `task`; the
410
421
  world is shared, never copied ({§machine-processes-fork-shares-the-world}).
@@ -419,7 +430,7 @@ literal `workers.name` value.
419
430
  parent's private entries — its own space deep-copied with the owner
420
431
  remapped (source → branch) — so the branch opens with the parent's notes and
421
432
  diverges on its own edits: *fork = everything-in-common-but-name*.
422
- - **Git branch batch** — `WORK[feature/x](worker://<name>):task` and `FORK[feature/x](worker://<name>):task` retain their worker meanings while placing the child in the serialized Git transaction defined by {§worker-branch-batch}. The signal is one branch ref, not tags; an untagged WORK/FORK keeps the ordinary concurrent shared-world behavior.
433
+ - **Git branch batch** — `## WORK0 [feature/x] (worker://<name>)` and `## FORK0 [feature/x] (worker://<name>)`, each with a task body, retain their worker meanings while placing the child in the serialized Git transaction defined by {§worker-branch-batch}. The signal is one branch ref, not tags; an untagged WORK/FORK keeps the ordinary concurrent shared-world behavior.
423
434
  - §worker-delegation-inherits-flags **Delegation inherits authority.** The live loop a spawn, fork, or irc-raised fresh loop starts with carries the **delegating loop's flags** — an auto parent delegates auto workers. Flags are a property of the delegation, not of a client binding: a child loop that fell back to defaults could propose side effects into a resolver-less headless review queue. An irc that *resumes* a parked loop leaves that loop's own flags untouched — inheritance applies only where a fresh loop is born.
424
435
  - §worker-lifecycle-wake-requeue-not-terminal **A wake re-queue is not a terminal.** A conclusion-wake resumes a 202-blocked loop by re-queueing it (202 → 100); when that lands while the loop's own live drain is between turns, the drain **re-claims and continues** (atomic 100 → 102; the injected prompt is already the next turn). The internal re-queue is never reported as an outward terminal.
425
436
 
@@ -453,7 +464,7 @@ sequenceDiagram
453
464
  participant B as Branch batch
454
465
  participant C1 as Child branch 1
455
466
  participant C2 as Child branch 2
456
- P->>B: WORK[branch-1], FORK[branch-2]
467
+ P->>B: WORK branch-1, FORK branch-2
457
468
  P->>G: queue exclusive before releasing shared turn
458
469
  G-->>B: all earlier turns drained
459
470
  B->>B: snapshot clean project repository; create both refs from frozen base
@@ -469,18 +480,18 @@ sequenceDiagram
469
480
 
470
481
  §worker-branch-batch-preflight **Preflight is total.** `GitMembership.projectRepository` resolves the repository containing `project_root`; absence rejects the tagged op. Earlier turns and finite derivation work drain at the exclusive boundary; a pre-existing open stream subscription is not a finite checkout operation and therefore rejects preflight rather than being silently cancelled or waited forever. Before any child starts, every branch passes `git check-ref-format --branch`, the project repository has no staged, unstaged, or nonignored untracked changes, every requested branch is absent, and the original symbolic ref/detached commit is recorded. All branch refs are then created from that frozen commit. Failure rolls back only refs created by this preflight, fails the queued children, restores the parent, and releases the workspace. Existing branches are never adopted or overwritten.
471
482
 
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.
483
+ §worker-branch-batch-return **A child returns commits, never a dirty checkout.** SEND signals `200`, `499`, and an already-drained `202` are refused with 409 while the project repository is off the assigned branch or dirty. The model commits or deliberately discards its changes and concludes again. On terminal, the batch records the full result commit and whether it differs from the frozen base, restores the exact original ref and commit, and only then advances. A clean child failure is a completed batch item and does not suppress later siblings; an ambiguous or dirty host failure becomes `recovery_required` and retains exclusivity because restoring would destroy or misattribute work.
473
484
 
474
485
  The active direct child's `Git Status` names its assigned branch and states the commit-and-clean return condition. No ordinary worker receives ambient commit or authorship policy; commit identity remains host-owned and outside model teaching. {§packet-git-status}
475
486
 
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.
487
+ §worker-branch-batch-receipt **The parent reconciles; the engine does not merge.** The ordinary child deliverable remains the model's exact SEND result. Its pushed termination delta and pull-side `## READ0 (worker://child)` append a bounded branch receipt to the presented body without changing that result: branch, item outcome, and the abbreviated result commit (`PLURNK_SERVICE_BRANCH_RECEIPT_REVISION_CHARS`; the database retains the full id). Branch refs remain after the batch. The parent chooses inspection, cherry-pick, merge, rejection, or deletion with ordinary Git tools.
477
488
 
478
489
  §worker-branch-batch-recovery **Recovery follows durable ownership.** `branch_batches`, their ordered items, the project-repository snapshot, and result tips are schema state, not process memory. Generic boot recovery never starts their queued loops. A crash before sealing fails the unstarted batch. A queued partial preflight is rolled back only when every created ref still equals its frozen base, then retried. A running child is never replayed: its loop settles under the ordinary owner-loss rule; if the checkout is clean and either on the assigned branch or the exact original position, the committed tip is retained, the original restored, that item marked interrupted, and queued siblings continue. Any mismatch becomes `recovery_required` and keeps the workspace stopped for operator correction.
479
490
 
480
491
  The remaining worker surfaces are:
481
492
 
482
- - **Entries (storage)** — entry addressing rides the authority carving above ({§worker-authority-carving}): `worker:///` the commons, `worker://~/` the own space, a name an ancestry-gated read ({§worker-read-scope}), writes own-space-and-commons only ({§worker-write-scoping}). An entry-path `KILL` deletes under the same write-scoping (200; 404 absent; 403 named) — distinct from the path-ABSENT `KILL(worker://<name>)` which terminates the worker ({§worker-scheme-terminate}); the discriminator is the entry path, never the op. A worker's own space is catalogued in ITS perspective alone (`FIND(worker://~/*)`, foisted at turn 0 even when empty); isolation is the owner column, structural.
483
- - §worker-scheme-terminate **Terminate** — `KILL(worker://<name>)` aborts a named worker and `KILL(worker://~)` aborts the caller: every unresolved loop in that worker's subtree closes 499 and every subscription in the subtree tears down; a literal name with no worker is 404. Cancellation is structured: descendants cannot detach implicitly. The override to the fire-and-forget default is not a parent-power — whoever holds the address may end it; a worker left alone simply ends at its own `SEND[200]`.
493
+ - **Entries (storage)** — entry addressing rides the authority carving above ({§worker-authority-carving}): `worker:///` the commons, `worker://~/` the own space, a name an ancestry-gated read ({§worker-read-scope}), writes own-space-and-commons only ({§worker-write-scoping}). An entry-path `KILL` deletes under the same write-scoping (200; 404 absent; 403 named) — distinct from the path-absent `## KILL0 (worker://<name>)` which terminates the worker ({§worker-scheme-terminate}); the discriminator is the entry path, never the op. A worker's own space is catalogued in its perspective alone (`## FIND0 [+init] (worker://~/*)`, foisted at turn 0 even when empty); isolation is the owner column, structural.
494
+ - §worker-scheme-terminate **Terminate** — `## KILL0 (worker://<name>)` aborts a named worker and `## KILL0 (worker://~)` aborts the caller: every unresolved loop in that worker's subtree closes 499 and every subscription in the subtree tears down; a literal name with no worker is 404. Cancellation is structured: descendants cannot detach implicitly. The override to the fire-and-forget default is not a parent-power — whoever holds the address may end it; a worker left alone simply ends at its own SEND signal `200`.
484
495
  - §worker-scheme-cap **Cap** — `PLURNK_SERVICE_WORKSPACE_WORKERS_MAX_ACTIVE` ceilings the *concurrent* active workers per workspace (a worker with a non-terminal loop); a spawn or fork past it fails hard (508 — no queue, no retry), irc exempt; `-1` disables it. The fork-bomb brake, sized for workspaces that live for months.
485
496
  - §worker-scheme-collect **Collect** — a worker's loop reaching a terminal status
486
497
  surfaces to its sisters as an ambient delta ({§env-delta}): a `SEND` from
@@ -491,9 +502,9 @@ The remaining worker surfaces are:
491
502
  non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly,
492
503
  so no termination is silent; collection is the shared world moving, never a
493
504
  verb. The **pull** side mirrors the push: a path-absent
494
- `READ(worker://<name>)` collects that same result on demand for a
505
+ `## READ0 (worker://<name>)` collects that same result on demand for a
495
506
  concluded worker; a worker **still running** has not delivered, so the READ
496
- returns **425** (Too Early) and the turn's bare `SEND[102]` **becomes a
507
+ returns **425** (Too Early) and the turn's bare SEND signal `102` **becomes a
497
508
  parked loop (202) on the join** ({§join-blocking-collect}) until the worker
498
509
  delivers — the engine holds the join, the model never drives a park. A
499
510
  missing name is 404. The model therefore reads the worker itself for its
@@ -511,7 +522,7 @@ The remaining worker surfaces are:
511
522
 
512
523
  ### §worker-loop-lifecycle Worker and loop lifecycle: drain, reap, and passive wake
513
524
 
514
- - §join-blocking-collect **A `READ` on a running child is a blocking join, not a poll.** A path-absent `READ(worker://<running-child>)` returns **425** (Too Early) and records a live obligation on the loop. The turn's bare `SEND[102]` is converted into an indefinite parked loop (202) instead of asking the model to poll or drive the scheduler. When the child reaches any terminal status, the same loop resumes with the result in its log. Children are bounded by their own turn and strike limits, terminal failure also wakes the parent, and the owed-wake path covers completion before the parent parks. Any `SEND` clears the per-turn arm; `SEND[200]` with a live child remains a premature-termination error. A `<seconds>` timeout-poll is the explicit polling alternative.
525
+ - §join-blocking-collect **A `READ` on a running child is a blocking join, not a poll.** A path-absent `## READ0 (worker://<running-child>)` returns **425** (Too Early) and records a live obligation on the loop. The turn's bare SEND signal `102` is converted into an indefinite parked loop (202) instead of asking the model to poll or drive the scheduler. When the child reaches any terminal status, the same loop resumes with the result in its log. Children are bounded by their own turn and strike limits, terminal failure also wakes the parent, and the owed-wake path covers completion before the parent parks. Any `SEND` clears the per-turn arm; SEND signal `200` with a live child remains a premature-termination error. A `<seconds>` timeout-poll is the explicit polling alternative.
515
526
 
516
527
  A worker is a **log plus a cancellation scope** — one `AbortController` per worker, reused while live and replaced only once aborted, so a cancel ends the worker as a unit and a later `runLoop` request is never born cancelled. A worker's queued loops are advanced by a **drain**: a single per-worker drain that claims loops atomically (status 100→102) and runs each under the worker's scope. A loop may spawn **streams** (execs) that outlive it; each is a row in the subscription registry ({§subscriptions}) — the durable record of what the worker holds open. Cancellation and conclusion are defined against these structures, never wall-clock timing.
517
528
 
@@ -532,8 +543,8 @@ stateDiagram-v2
532
543
  §stream-catalog-lifecycle Streams are independently durable subscriptions owned by a worker. Payload and
533
544
  lifecycle are orthogonal: zero bytes is a valid payload for both success and
534
545
  failure, while the closed subscription and its status are the terminal fact.
535
- Every stream entry exposes that durable state in catalog rows as
536
- `stream: { state, ... }`: active streams carry `seconds`; terminal streams carry
546
+ Every stream entry exposes that durable state on its catalog group's default
547
+ channel (`[0].stream: { state, ... }`): active streams carry `seconds`; terminal streams carry
537
548
  their exact `status` and derive `closed` (status below 400), `killed` (499), or
538
549
  `failed` (other failure status). An entry with no subscription has no `stream`
539
550
  member. This is historical state, not merely a live-process hint.
@@ -552,7 +563,7 @@ stateDiagram-v2
552
563
  Observed --> [*]
553
564
  ```
554
565
 
555
- | §worker-lifecycle-subscription-matrix Subscription state at `SEND[202]` | Terminal observation already in a packet | Result |
566
+ | §worker-lifecycle-subscription-matrix Subscription state at SEND signal `202` | Terminal observation already in a packet | Result |
556
567
  |-------------------------------------------------------------------------|---:|---|
557
568
  | open | no | park; polling or closure may wake it |
558
569
  | closed, any status, empty or non-empty | no | continue directly to the observation turn |
@@ -579,9 +590,9 @@ sequenceDiagram
579
590
  participant C as Child loop
580
591
  participant S as Child stream
581
592
  P->>C: WORK or FORK
582
- P->>P: SEND[202] parks on live child
593
+ P->>P: SEND 202 parks on live child
583
594
  C->>S: EXEC opens subscription
584
- C->>C: SEND[202] parks on live stream
595
+ C->>C: SEND 202 parks on live stream
585
596
  loop backoff, fixed cadence, or explicit arrival
586
597
  S-->>C: optional progress observation
587
598
  C->>C: continue or park
@@ -602,9 +613,9 @@ sequenceDiagram
602
613
  | cancelled or failed terminal | no | same wake/delivery path as success; outcome remains non-2xx |
603
614
 
604
615
  A stream's close status and a loop's terminal status are separate layers. A
605
- stream may close 4xx/5xx and wake its worker to recover. Model `SEND[4xx/5xx]`
606
- reports a failed action and continues; `SEND[200]` concludes successfully and
607
- `SEND[499]` explicitly abandons the worker. Only a concluded loop crosses the
616
+ stream may close 4xx/5xx and wake its worker to recover. Model SEND signals
617
+ `4xx/5xx` report a failed action and continue; signal `200` concludes successfully and
618
+ signal `499` explicitly abandons the worker. Only a concluded loop crosses the
608
619
  parent edge as the child's result.
609
620
 
610
621
  §worker-lifecycle-terminal-result **Terminal truth is a result, not a lifecycle code.** `loops.terminal_result`
@@ -640,16 +651,16 @@ observe their terminal results. No effect is replayed across an unknown
640
651
  boundary.
641
652
 
642
653
  - §worker-lifecycle-single-drain **One drain advances a worker.** At most one drain is registered for a worker at any instant: a `runLoop` request or wake on a worker with a live drain folds in (active→next-turn) or enqueues a loop that drain claims, never a second parallel drain. A drain's start and its empty-queue teardown relinquish the worker under one per-worker lock, so the teardown's re-claim cannot race a concurrent start into a double-drain. Fresh-loop sequence allocation and insertion are one mutation under that same lock; concurrent accepted prompts remain distinct ordered queue items.
643
- - §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel`, worker `KILL`, shutdown, and a worker's `SEND[499]` terminalize every unresolved loop in the cancelled worker subtree and iterate each worker's durable open-subscription rows, invoking each exact callable owner from the process-local live registry. The durable rows answer *what is held*; the live registry answers *how this process tears it down*; the abort signal is a fast-path optimization. There is no implicit detachment. Before shutdown awaits drains, it cancels every process-local proposal waiter through {§proposal-cancel-aborts} with outcome `daemon_stopping`, so a stopped-world dispatch cannot hold teardown open. A stream that is running, mid-spawn (its row written before it is killable), or spawned after the cancel is reaped alike. The teardown abort is bounded: the executor sends a polite signal then SIGKILL after a consumer-set grace (`PLURNK_SERVICE_EXEC_KILL_GRACE_MS`). A model `KILL[code]` on one live stream instead delivers exactly that signal once (bare `KILL` the executor's SIGHUP default, `KILL[9]` SIGKILL).
654
+ - §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel`, worker `KILL`, shutdown, and a worker's SEND signal `499` terminalize every unresolved loop in the cancelled worker subtree and iterate each worker's durable open-subscription rows, invoking each exact callable owner from the process-local live registry. The durable rows answer *what is held*; the live registry answers *how this process tears it down*; the abort signal is a fast-path optimization. There is no implicit detachment. Before shutdown awaits drains, it cancels every process-local proposal waiter through {§proposal-cancel-aborts} with outcome `daemon_stopping`, so a stopped-world dispatch cannot hold teardown open. A stream that is running, mid-spawn (its row written before it is killable), or spawned after the cancel is reaped alike. The teardown abort is bounded: the executor sends a polite signal then SIGKILL after a consumer-set grace (`PLURNK_SERVICE_EXEC_KILL_GRACE_MS`). A model `## KILL0 [code]` on one live stream instead delivers exactly that signal once (bare KILL uses the executor's SIGHUP default; `## KILL0 [9]` uses SIGKILL).
644
655
  - §worker-lifecycle-exec-epoch-bound **A stream's kill binds to the scope it captured at spawn.** A stream captures the worker's cancellation scope as it registers and wires its kill to it, re-checking `aborted` AFTER wiring — no check-then-listen gap can drop an abort that lands mid-registration. Because the scope is replaced only once aborted, a captured-then-replaced scope is necessarily already aborted, so replacement never strands a live stream.
645
656
  - §worker-lifecycle-no-resurrection **A cancelled worker is not resurrected by its own torn-down work.** A stream conclusion delivered to a cancelled, idle worker starts no fresh drain: an aborted (499) conclusion is skipped, and a straggler that concluded cleanly surfaces its deliverable as an environment delta ({§env-delta}), never a revived loop. The cancel was deliberate; only an explicit `runLoop` request resumes the worker.
646
657
  - §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** When a backgrounded stream concludes, the daemon routes it through the same inject seam as any loop source ({§actor-boundary-passive-wake}): an active worker folds the conclusion into its next turn; a worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) **awakens that loop in place** — the blocked loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. The result is never lost: a blocked loop sleeps rather than ending, and the stream's status-transition is the arrival ({§actor-boundary-passive-wake}) that wakes it; on resume it reads the concluded stream's own state, not a synthetic prompt.
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.)
658
+ - §worker-lifecycle-child-wake **A child worker concluding wakes a parent blocked on it — the topology join.** `worker://` spawn/fork records `parent_worker_id` ({§lifecycle-terms}). When a worker's drain exits having **concluded** — no `202`-blocked loop, no open stream — the daemon resumes its parent **in place** if the parent is blocked on the join (`#onDrainExit` → the shared `#wakeParkedWorker`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and blocks with SEND signal `202` is woken the moment its child finishes; on resume it reads the child's deliverable from the {§worker-scheme-collect} delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself blocked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child workers are the same kind of "live thing a worker holds," driving premature-terminate ({§send-premature-terminate}), the wake edge, and the collect delta identically. A worker conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its block commits), `#wakeParkedWorker` finds it not-yet-slept and records an **owed wake**, which the drain honors when the parent blocks — so a wait awaiting workers **always returns**, never dead-blocks on a conclude-before-block race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a wait open.)
648
659
  - §worker-optimistic-settlement **Asynchronous settlement receives one bounded worker-local opportunity before model dispatch.** An initiating turn lets only the streams it started settle before its terminal SEND; separately, a stream or direct-child conclusion persists and publishes immediately but holds the parked worker's single `202→100` requeue while another stream or direct child remains live. Both use `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`, shipped at five seconds; zero disables the opportunity. The wake hold ends as soon as no sibling obligation remains, never extends its original deadline, and coalesces every conclusion that lands within it into one requeue. With no sibling obligation the wake is immediate; at the deadline, surviving work follows the ordinary monitored lifecycle. A conclusion that lands after provider dispatch begins retains its next wake, while poll, park-deadline, prompt, and operator wakes never open this hold. Only packet/provider dispatch waits: terminal state, client events, cancellation, and child execution do not. One redaction-safe span records elapsed time, quiescence versus deadline, and conclusion count without entering the packet.
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.
660
+ - §worker-lifecycle-idle-is-concluded **An idle worker concludes; it does not park.** A loop is idle only when it has neither live obligations nor completed results awaiting their first packet. A live child or stream blocks a SEND signal `202` join; a completed stream, child result, or same-turn retrieval continues directly to the next packet where it is observed. Only after those sets are drained does signal `202` resolve like signal `200`. There is no held-open idle loop and no `loop/quiesced` soft signal. A concluded worker is durable working history and an addressed arrival reawakens it as a new loop.
650
661
  - §worker-lifecycle-no-lost-loop **A loop is never stranded by a drain's exit.** A drain relinquishes its registry slot only after a lock-held re-claim confirms the queue is empty; a loop enqueued during that teardown is either re-claimed by the exiting drain or claimed by a fresh drain that a later inject starts. The relinquish and the start are serialized, so neither the lost-loop hang nor a transient double-drain can occur.
651
662
  - §worker-lifecycle-durable-disposition **Durable disposition wins cancellation races.** At a turn boundary, the engine reads the loop's durable status before interpreting a process-local abort. A committed `202` park survives a later daemon-shutdown signal; only a loop still durably running at `102` can be terminalized by that cancellation.
652
- - §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every durable proposed operation likewise lost its process-local resolution waiter and settles as a visible `500 owner_vanished` occurrence rather than an unresolvable interrupt ({§proposal-list}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation survives only while a live child obligation remains; after reconciliation, an unblocked park requeues `202→100` and resumes in place. Child terminalization wakes its parked parent on every outcome, including provider exceptions, cancellation, and restart interruption, recursively through the durable parent edges. These operations are idempotent, so an interrupted recovery safely repeats.
663
+ - §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every pending physical provider request beneath that loop first settles as an error with absent usage and explicitly unknown cost, then its logical model call closes; recovery never fabricates zero evidence. Every durable proposed operation likewise lost its process-local resolution waiter and settles as a visible `500 owner_vanished` occurrence rather than an unresolvable interrupt ({§proposal-list}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation survives only while a live child obligation remains; after reconciliation, an unblocked park requeues `202→100` and resumes in place. Child terminalization wakes its parked parent on every outcome, including provider exceptions, cancellation, and restart interruption, recursively through the durable parent edges. These operations are idempotent, so an interrupted recovery safely repeats.
653
664
 
654
665
  ---
655
666
 
@@ -659,13 +670,12 @@ Author-facing contract: [`@plurnk/plurnk-providers`](../plurnk-providers/SPEC.md
659
670
 
660
671
  ### §provider-surface Consumption surface
661
672
 
662
- Three current entry points:
673
+ Two current entry points:
663
674
 
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}).
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.
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.
675
+ - §provider-surface-generate `provider.generate(args)` — once per logical model call. An emission attempt supplies the complete packet messages, worker/turn coordinates, generation envelope, optional local grammar, first-party metadata, and `callKind: "emission"`. A BARE inference supplies only one user message containing its body plus non-prompt call identity and accounting metadata, including `callKind: "bare"` ({§bare-inference} {§provider-call-kind}). Both receive a durable physical-request observer; provider-owned retry and failover may issue several ordered requests beneath either call. A successful `ProviderResponse` reaches its call-specific consumer; a `ProviderError.attempt` remains failed response evidence under {§provider-interrupted-attempt}. Core persists normalized response evidence separately from physical accounting and relays encrypted reasoning only from an admitted emission ({§encrypted-reasoning-carrier}).
676
+ - §provider-surface-prompt-measurement `provider.countPromptTokens(messages, signal)` — cancellable measurement of the complete provider request with `exact`, `upper_bound`, or `estimate` provenance. It is used only for hard context-envelope admission ({§tokenomics-context-envelope-admission}); model-facing stored and rendered weights use the provider-agnostic ruler.
667
677
 
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}).
678
+ §provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow` (the effective total context envelope, or `null` when unknown) and the optional reasoning/completion reserves define the natural prompt partition and hard admission check ({§tokenomics}); `model` identifies persisted turn/provider evidence. Local GBNF boot verification also consumes `constrainsOutput` ({§grammar-enforcement-verified-at-boot}).
669
679
 
670
680
  §meta-passthrough **Metadata passthrough (provider → client).** `generate` may return an open `meta: Record<string, unknown>` bag. The service stores it unenforced per turn (`turns.meta`, `json_valid` only — no schema) and forwards the latest turn's blob in `loop/terminated.usage` ({§notifications}). The service never reads a field within it. Providers own their metadata shapes; monetary values carry an explicit amount and currency rather than an implied unit. Absent → `{}`. The mirror direction (client → provider, the self-identified `client` id) rides `generate({client})` ({§attribution}).
671
681
 
@@ -674,18 +684,20 @@ Three current entry points:
674
684
  - `messages` is a complete prompt (the section list, pre-assembled into the system + user messages). Provider does not reorder.
675
685
  - §provider-guarantees-signal-wired `signal` is wired to the worker's AbortController.
676
686
  - §provider-guarantees-serial-attempts Emission attempts for one engine turn are serial. They reuse the exact messages, coordinates, generation limits, and strike state; two attempts for that turn never overlap.
687
+ - BARE calls admitted by one turn launch as one parallel batch; each call retains independent observer and failure state, and the engine awaits the complete batch before committing results in authored order ({§bare-inference}).
688
+ - §provider-guarantees-request-observer Immediately before each physical provider I/O, the provider opens its provider/model identity through `observeRequest` and settles the returned handle exactly once as response or error. Core durably records that occurrence before I/O and rejects a returned response or `ProviderError` whose ordered accounting differs from the observed records. Persistence failure is an internal contract failure, never optional telemetry.
677
689
  - §provider-guarantees-assistantraw-opaque `assistantRaw` is opaque to the engine (forensics-only).
678
- - `countPromptTokens` receives the exact `PacketWire` messages later supplied to `generate`. The engine calls it only for an over-policy recovery candidate; it may perform provider I/O and receives the loop cancellation signal.
690
+ - `countPromptTokens` receives the exact `PacketWire` messages later supplied to `generate`. The engine calls it only when negative ruler pressure requires hard context-envelope admission; it may perform provider I/O and receives the loop cancellation signal.
679
691
 
680
692
  ### §emission-admission Provider emission admission
681
693
 
682
694
  A completed provider exchange is an **emission attempt**, not necessarily an engine turn. The provider transports and observes the model's bytes; ANTLR is the admission authority only after provider completion. Admission asks whether the exchange has a trustworthy frame: its first parsed operation is PLAN, its last parsed operation is a terminal SEND, every hard parse error is bounded between those anchors, and no `unparsedTail` exists. Missing anchors, an error outside the frame, or a boundary-destroying tail rejects the entire exchange regardless of `finishReason`; no recovered prefix dispatches. Parser warnings remain admissible. `finish=length` is forensic evidence of likely truncation, not an independent rejection rule. A provider-declared resource interruption never reaches admission, even when its partial bytes form a complete-looking frame ({§provider-interrupted-attempt}).
683
695
 
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.*`.
696
+ Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch or reach the engine strike rail. Before each `generate`, Core opens one durable logical `model_calls` row and its emission-specific `turn_attempts` admission row. Beneath the model call, every provider observer invocation opens one cardinal `provider_requests` occurrence immediately before physical I/O and settles it as response or error. Adapter retries and capacity failover append requests in issue order; a response-less failure therefore remains an accounted occurrence rather than disappearing. Normalized response evidence is durable before parser classification and does not duplicate the separately owned accounting. The accepted exchange alone completes `turns.packet`; every physical request remains in turn and loop accounting, while the context gauge reads the latest settled emission request on the latest turn. Digest exposes rejected response evidence as `packetNNN.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
685
697
 
686
698
  The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED model item under {§model-entry-log-curation} and carries one transient `invalid_emission` Notice whose complete message is: `Your previous response contained an unrecoverable syntax error. No operations were performed. Try again.` No parser diagnostic, attempt count, or rail state becomes model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
687
699
 
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.
700
+ An admitted frame may contain bounded malformed statements. Parsed operations still dispatch; each malformed statement becomes one durable model-origin `error` row with the parser's exact diagnostic under {§parse-diagnostics} and status 400. These failures are committed before the terminal disposition, participate in the ordinary strike rail, and prevent SEND signal `200` or an already-drained signal `202` from concluding before the model sees them in the next packet. This is operation recovery, not provider resampling.
689
701
  The Problem recovery states that only the failed operation needs correction
690
702
  because its parsed siblings were retained; the parser-owned detail states the
691
703
  specific syntax rule.
@@ -697,10 +709,12 @@ terminates the loop at 500 without spending an engine strike.
697
709
  §turn-never-blank An admitted turn whose operation fails — during parsing or
698
710
  dispatch — is categorically different: its failed operation row enters
699
711
  model-visible history and the next engine turn may recover. A `ProviderError`
700
- means no completed exchange exists (auth, network beyond provider retries,
701
- rate limit, or provider-declared interruption). When the error carries
702
- interrupted attempt evidence, core stores it unaccepted with its usage and cost;
703
- the failed turn still stores the exact request and never fabricates an assistant.
712
+ means no exchange was admitted (auth, exhausted transport retries, rate limit,
713
+ or provider-declared interruption). Core settles and retains every physical
714
+ request's known or unknown {§provider-request-accounting}; when the error carries
715
+ interrupted response evidence, Core stores it unaccepted without duplicating its
716
+ accounting. The failed turn still stores the exact request and never fabricates
717
+ an assistant or a zero-valued observation.
704
718
 
705
719
  ### §attribution Plugin-authored attribution folksonomy
706
720
 
@@ -713,10 +727,10 @@ shared contract {§plugin-attribution}:
713
727
 
714
728
  | Stage | Contract |
715
729
  | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
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. |
730
+ | Collection | Immediately before each emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. A BARE call pulls only its selected provider source because it admits no other plugin capability. |
717
731
  | Composition | Core flattens, deduplicates, and sorts the tags. The resulting non-empty array rides `generate({ attributions })`; an empty set omits that provider field. |
718
732
  | Meaning | Core neither verifies nor infers contribution. Tags are plugin-authored folksonomy for telemetry, optimization, attribution, or downstream rules. The `@plurnk/` reservation is the only namespace policy ({§plugin-attribution}). |
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. |
733
+ | Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Every pre-I/O `model_calls` row carries that call's exact set, including response-less failures. |
720
734
  | Derived reporting | Turn, loop, digest, and client views project the recorded sets. `loop/terminated.attributions` is their deduplicated sorted union and remains separate from provider usage and charge evidence. |
721
735
 
722
736
  Runtime hooks are synchronous and receive only the attempt coordinates. A hook
@@ -741,16 +755,20 @@ plugin discovery is the last protocol-extension seam.
741
755
  The ANTLR grammar always defines and validates the PLURNK language. Separately,
742
756
  an operator may configure `PLURNK_PROVIDERS_GBNF_<alias>` for a local
743
757
  llama-server. The provider must advertise GBNF transport and satisfy a forcing
744
- probe whose pre-projection sentence is one reasoning enclosure followed by the
745
- `PLURNK-RAILS-LIVE` sentinel, or boot fails. The setting is resolved
758
+ probe whose sampled sentence and pre-projection response match the selected
759
+ rail's template boundary followed by the `PLURNK-RAILS-LIVE` sentinel, or boot
760
+ fails. The setting is resolved
746
761
  per alias and is unset by default. Configuring it on a cloud or endpoint-managed
747
762
  provider is an error, not a request for best-effort filtering.
763
+ Alias-scoped `PLURNK_PROVIDERS_GBNF_DEBUG` deliberately withholds transport, so
764
+ boot skips the enforcement probe while real requests retain the configured rail
765
+ for local syntax validation and the engine's withheld-rail verdict.
748
766
  Runtime injection uses the provider's registered alias, falling back only to
749
767
  the process's active alias. Suffixed rail settings with neither identity fail
750
768
  instead of guessing. A configured package variant or explicit path that cannot
751
769
  be loaded also fails; it never silently becomes unconstrained.
752
770
 
753
- §gbnf-requires-reasoning The shipped PLURNK rail requires reasoning. The same alias-scoped configuration
771
+ §gbnf-requires-reasoning Both shipped PLURNK rails require reasoning. The same alias-scoped configuration
754
772
  must resolve reasoning to `adaptive` or `on`; `off` with GBNF is rejected before
755
773
  the probe or any model generation. Reasoning-off remains valid when no GBNF rail
756
774
  is configured.
@@ -758,7 +776,8 @@ is configured.
758
776
  §rail-truth-engine-verdict **Local constraint truth is independently observed.**
759
777
  For a configured local GBNF, the provider returns the pre-projection sentence as
760
778
  `grammarEvidence` under `plurnk-providers` {§gbnf-response-observation}. The engine
761
- requires that evidence, independently validates `grammarEvidence.input`, and
779
+ requires that evidence, independently validates `grammarEvidence.input` with the
780
+ artifact's declared response root, and
762
781
  stamps `railsAttached: "client"` when transported or `"withheld"` in debug mode
763
782
  plus `railsVerdict`; it never validates projected
764
783
  `assistant.content` as though the required reasoning enclosure were still
@@ -859,7 +878,7 @@ Every fact names the canonical key, never the host root or an echo of the
859
878
  model's spelling. These classes let a caller distinguish a wrong address, an
860
879
  invalid range, read-only authority, and occupied hidden state without guessing.
861
880
 
862
- §fs-world-state **The world-state harness — coverage that closes the class.** Op-outcome tests check what an op returned; the harness checks the resulting world. `WorldState.check(db)` asserts, pure-db and read-only: identity uniqueness in practice (no tuple holds two rows), the canonical fixpoint on every file-class key, orphan-freedom (channels/tags without parents), the closed admission set (a file row's grantor is git or a client act — or the create-accepted transient NULL the next reconcile stamps), and sig-coherence. It runs as a lifecycle-test epilogue and at every soak turn boundary, where the delta half applies: an idle turn grows the entries table by ZERO. A violation names its law and its row.
881
+ §fs-world-state **The world-state harness — coverage that closes the class.** Op-outcome tests check what an op returned; the harness checks the resulting world. `WorldState.check(db)` asserts, pure-db and read-only: identity uniqueness in practice (no tuple holds two rows), the canonical fixpoint on every file-class key, channel orphan-freedom, the closed admission set (a file row's grantor is git or a client act — or the create-accepted transient NULL the next reconcile stamps), and sig-coherence. It runs as a lifecycle-test epilogue and at every soak turn boundary, where the delta half applies: an idle turn grows the entries table by ZERO. A violation names its law and its row.
863
882
 
864
883
  ### §scheme-manifest Manifest
865
884
 
@@ -890,9 +909,11 @@ Registration precedes loop affinity:
890
909
  | Registered but inactive under flag | The flag gate returns `403 scheme-unavailable`. |
891
910
  | Registered and active | Dispatch continues to the operation owner. |
892
911
 
893
- - §op-mode-phases **A continuing turn executes in MODE phases.** A model turn describes intended effects and requested observations; it is not an imperative program whose later statements can consume invisible same-turn results. The engine therefore performs four stable phases: **Mutate** (`EDIT`, `COPY`, `MOVE`, `KILL`, `FOLD`), **Observe** (`FIND`, `READ`, `OPEN`), **Do** (all remaining non-terminal actions, including `EXEC`, `WORK`, `FORK`, and directed `SEND`), then **End** (the terminal `SEND`). `PLAN` remains the turn anchor and is recorded before those phases. Authored order is preserved within each phase. A result still lands in the next packet; phasing makes that result describe settled state instead of an accidental intermediate state.
912
+ - §op-mode-phases **A continuing turn executes in MODE phases.** A model turn describes intended effects and requested observations; it is not an imperative program whose later statements can consume invisible same-turn results. The engine therefore performs four stable phases: **Mutate** (`EDIT`, `COPY`, `MOVE`, `KILL`, `FOLD`), **Observe** (`FIND`, `READ`, `OPEN`, `BARE`), **Do** (all remaining non-terminal actions, including `EXEC`, `WORK`, `FORK`, and directed `SEND`), then **End** (the terminal `SEND`). `PLAN` remains the turn anchor and is recorded before those phases. Authored order is preserved within each phase. A result still lands in the next packet; phasing makes that result describe settled state instead of an accidental intermediate state.
894
913
 
895
- - §op-synchronous **Decisive operations settle before the next scheduled operation.** The dispatcher `await`s every decisive operation. Work remains in flight only when the operation's contract deliberately creates concurrency: `FORK`, `WORK`, stream-producing `EXEC`, and a streaming `READ` after its scheme-specific acquisition boundary. Such a READ first establishes its durable subscription, returns `102`, and then retains only its `StreamSubscription`; a later scheduled operation may address that live owner. MODE changes scheduling, not completion semantics. This is why a same-turn `KILL + SEND[200]` concludes ({§send-premature-terminate}): `KILL` synchronously flips the worker's live loops terminal (`engine_terminate_worker_live_loops`) before the End phase judges the pending set, while the physical scope reap rides `cancelWorker` asynchronously and invisibly.
914
+ §bare-inference **BARE is isolated, synchronous retrieval over the durable child-provider policy.** Its body is the complete prompt and becomes the sole user message; Core supplies no PLURNK system packet, log context, tools, GBNF, parser, target, worker, or persistent child state. The selected provider is exactly the loop's WORK/FORK child provider, falling back to the parent provider when the durable policy is inherit. All BARE statements in one admitted turn receive logical model-call identities in authored order and launch concurrently under the loop cancellation signal. Core awaits the batch, isolates a provider failure to that operation, then records results and notifications in authored order regardless of completion order. Accounting or persistence failure is internal and fails hard. Each response is unseen retrieval work: the canonical disposition is `SEND[102]`, and same-turn `SEND[200]` is refused until the next packet presents it.
915
+
916
+ - §op-synchronous **Decisive operations settle before the next scheduled operation.** The dispatcher `await`s every decisive operation. Work remains in flight only when the operation's contract deliberately creates concurrency: `FORK`, `WORK`, stream-producing `EXEC`, and a streaming `READ` after its scheme-specific acquisition boundary. Such a READ first establishes its durable subscription, returns `102`, and then retains only its `StreamSubscription`; a later scheduled operation may address that live owner. MODE changes scheduling, not completion semantics. This is why a same-turn KILL followed by SEND signal `200` concludes ({§send-premature-terminate}): KILL synchronously flips the worker's live loops terminal (`engine_terminate_worker_live_loops`) before the End phase judges the pending set, while the physical scope reap rides `cancelWorker` asynchronously and invisibly.
896
917
 
897
918
  - §edit-batch **Same-resource EDITs are one mutation.** Every EDIT targeting the same canonical resource and channel in one turn applies to the resource's one pre-turn snapshot. The scheme validates the complete batch before writing, applies disjoint replacements from the highest original coordinate downward, and commits one resulting revision atomically; reversing the statements cannot change that revision. A failing statement rejects that resource batch without a partial write; independent resource batches remain independent. Whole-resource replacement or creation cannot coexist with another EDIT in the same batch, selected regions may not overlap, and a zero-length insertion may occur at most once at each boundary. Prepend (`<0>`), append (`<-1>`), and exact equal-endpoint insertions compose with non-overlapping replacements. Proposal-gated schemes expose one proposal for the resource batch and accept all or none. The public scheme contract is batch-shaped: a scheme must never emulate this guarantee by applying individual EDITs sequentially.
898
919
 
@@ -926,14 +947,14 @@ Details state `destinationWritten: true` and identify the destination.
926
947
 
927
948
  Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
928
949
 
929
- - `SEND[200](path)` — write body into resource (WS message, exec stdin).
930
- - `SEND[499](path)` — cancel active subscription ({§stream}).
950
+ - `## SEND0 [200] (path)` — write body into resource (WS message, exec stdin).
951
+ - `## SEND0 [499] (path)` — cancel active subscription ({§stream}).
931
952
 
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.
953
+ - §log-uniform-query **Log speaks the universal query contract** — `## FIND0 (log://…)` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~semantic` and `@graph` use the same persistent derivation artifacts and candidate rankers as entries. Broad results are one-channel catalog groups whose `[0].path` is `log:///loop/turn/seq/OP`; exact matcher results are flat locations ({§find-result-projection}). A FIND signal classifies the FIND result row and never changes this candidate set ({§log-item-tags}). Log remains the core event ledger rather than duplicating rows into `entries`; its core-private storage adapter supplies one complete channel representation to the same READ projector. That adapter is not a plugin seam and grants no protocol scheme an alternate READ path.
933
954
  - §find-source-agnostic **The content matcher is source-agnostic** — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND works uniformly across schemes by construction: `EntryFind` and `Log.find` run the one shared primitive rather than re-implementing it per scheme. Log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
934
955
  - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{locator?,region?}`. `locator` preserves a structural address without overloading the resource row's `path`; `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. FIND alone decides whether that grouped selection projects as resource rows or flat locations ({§find-result-projection}); the engine never fabricates a region or guesses which surgical READ the model wants.
935
956
 
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}).
957
+ `## SEND0 [410] (path[#fragment])` also deletes the target entry/channel — an implemented side-effect, NOT taught to the model and with no live/demo surface. The model-facing delete idiom is KILL ({§move}).
937
958
 
938
959
  §send-dispatch-entry-schemes-501-on-non-410 Other status codes return 501 from entry-bearing schemes by default.
939
960
 
@@ -971,7 +992,7 @@ Engine → scheme guarantees:
971
992
  - §universal-read-composition **Exact READ has one composition.** Core resolves
972
993
  canonical identity and owner once, gives a data scheme its optional
973
994
  `prepareRepresentation({ target, pathname })` opportunity, reads the complete
974
- canonical channels and tags, selects the authored channel, applies binary and
995
+ canonical channels, selects the authored channel, applies binary and
975
996
  text-coordinate rules, and finally composes that channel's durable producer
976
997
  result. Preparation receives neither fragment nor `lineMarker`; finite work
977
998
  returns `200`, while only a retained live representation may return `102`
@@ -1087,8 +1108,8 @@ discovery ({§mimetype-discovery}).
1087
1108
  projection is independent of packet budgeting. Core uses the stable
1088
1109
  model-independent ruler for stored/catalog weights and the model-facing budget
1089
1110
  ({§tokenomics-agnostic-ruler}). The provider's request-shaped measurement is
1090
- confined to provider-physical recovery admission
1091
- ({§tokenomics-physical-admission}).
1111
+ confined to hard context-envelope admission
1112
+ ({§tokenomics-context-envelope-admission}).
1092
1113
 
1093
1114
  §persistent-search-index **Persistent search index.** `SearchIndex.maintain` is the pre-model engine pass. Each searchable resource supplies an address and the exact readable body its READ exposes. Entries supply their default body; `LogBody` resolves each log row's canonical full body from its durable tx/rx envelope. Acquisition schemes project remote source material before storing that body; search never introduces a second hidden text projection. The readable body, mimetype, resolved text/binary classification, mimetype projection identity, embedder configuration, and applicable search exclusion form a content hash. Complete artifacts own FTS, vectors, symbol definitions, and references; resource rows hold only the attachment hash. Binary, empty, and excluded derivations do not invoke handler projections and therefore use one fixed no-projection identity.
1094
1115
 
@@ -1159,7 +1180,7 @@ A published default channel renders under the entry's ordinary fragmentless addr
1159
1180
 
1160
1181
  ### §no-visibility Entries carry no visibility
1161
1182
 
1162
- Every entry is uniformly listed in the catalog (`FIND(scheme:///**)`, {§packet}) and READable — entries have no per-worker open/folded state. Context curation is the model's, on the **log** (via OPEN/FOLD, {§open-fold}), never on entries.
1183
+ Every entry is uniformly listed in the catalog (`## FIND0 (scheme:///**)`, {§packet}) and READable — entries have no per-worker open/folded state. Context curation is the model's, on the **log** (via OPEN/FOLD, {§open-fold}), never on entries.
1163
1184
 
1164
1185
  ### §channel-mimetype Mimetype is a (scheme, channel) property — never a default
1165
1186
 
@@ -1193,14 +1214,7 @@ Op implications:
1193
1214
 
1194
1215
  Client-interface target parameters carry fragments inline (`{ target: "sh:///1/1/2#stderr" }`).
1195
1216
 
1196
- **Wire rendering: default channel is path-only.** Heredoc fence omits `#channel` when channel matches `defaultChannel`. Single-channel entries render path-only; multi-channel entries render the default path-only and only non-default carries `#name`.
1197
-
1198
- ```
1199
- <<notes.md:...:notes.md — file scheme (bare)
1200
- <<sh:///1/1/2:...:sh:///1/1/2 — exec output default (stdout)
1201
- <<sh:///1/1/2#stderr:...:sh:///1/1/2#stderr — non-default
1202
- <<log:///1/1/0:...:log:///1/1/0 — atomic log row
1203
- ```
1217
+ **Wire rendering: default channel is path-only.** A rendered target omits `#channel` when channel matches `defaultChannel`. Single-channel entries render path-only; multi-channel entries render the default path-only and only non-default carries `#name`.
1204
1218
 
1205
1219
  ### §channel-state Channel state — metadata, not gating
1206
1220
 
@@ -1221,17 +1235,68 @@ Model uses state to anticipate growth between turns. Clients use state for UI (s
1221
1235
 
1222
1236
  Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkStatement`. Engine dispatches by `op`; scheme implements per author contract ({§scheme}).
1223
1237
 
1238
+ ### §line-anchors Text line anchors
1239
+
1240
+ A scheme declaring `textEditScopes: true` with model write authority publishes
1241
+ the contracts-owned {§text-line-anchor-syntax}. For canonical model-facing
1242
+ resource identity `R`, one-based line ordinal `L`, configured non-negative
1243
+ neighbor count `C`, and ordered content array `W` containing that line and up to
1244
+ `C` complete lines on either side (all excluding separators), core hashes the
1245
+ JSON tuple `["plurnk-line-anchor-v1",R,L,C,W]` with SHA-256, interprets the
1246
+ digest as a big-endian integer modulo `62^5`, and encodes five fixed-width
1247
+ characters with alphabet `0-9A-Za-z`. The universal READ projector derives
1248
+ anchors from the complete canonical selected channel before applying the
1249
+ authored text slice; its durable result retains the canonical derivation
1250
+ identity and anchors aligned with returned lines. Packet rendering right-aligns
1251
+ `L` to the decimal width of the complete canonical selected channel's final
1252
+ addressable line and emits `@xxxxx L:<content>` with one or more ASCII spaces
1253
+ before `L`; a source line therefore retains the same prefix across projections
1254
+ of one revision.
1255
+ An explicit default-channel fragment and its fragmentless spelling share that
1256
+ identity; a selected non-default channel retains its canonical `#channel`.
1257
+
1258
+ For READ/LOOK and COPY/MOVE source or destination selection, core resolves every
1259
+ anchor against the addressed current complete content before applying the
1260
+ ordinary numeric text-coordinate contract. Exactly one current match lowers to
1261
+ its numeric line; zero or multiple matches return 409 `line-anchor-collision`,
1262
+ and an anchor in a column position returns 400. COPY/MOVE mutation owners retain
1263
+ the resolved endpoint neighborhoods as compare-and-swap preconditions. There is
1264
+ no revision sidecar or fuzzy relocation. A range authenticates both endpoint
1265
+ neighborhoods, so every line of a range up to `2C + 2` lines is covered; a
1266
+ longer range retains an unauthenticated interior gap. The shipped `C = 2`
1267
+ covers ranges through six lines.
1268
+
1224
1269
  ### §edit EDIT
1225
1270
 
1226
- AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker? }`.
1271
+ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker?: TextLineMarker }`.
1227
1272
 
1228
1273
  - Resolves target channel from fragment ({§channel-selection}); unknown channel → 400; undeclared in manifest → engine crash ({§channel-mimetype}).
1229
1274
  - §edit-null-clears Writes the body; `body: null` clears it.
1230
1275
  - §edit-status-201-200 Returns `{ status: 201, entryId }` for a new entry and
1231
1276
  `{ status: 200, entryId }` for a content update.
1232
- - §edit-noop-304 A write that changes nothing — identical content and no new tag — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's idempotence ({§open-fold}).
1233
- - §edit-tags-additive Tags from `signal[]` apply additively via `entry_tags` (scheme may vary).
1277
+ - §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's idempotence ({§open-fold}). The operation's log classification remains independent ({§log-item-tags}).
1234
1278
  - §edit-marker-required-on-existing **A markerless EDIT is CREATE-ONLY — there is no easy-clobber path on an existing entry.** A `<L>` marker scopes an EDIT to a range; without one, the body becomes the entry's WHOLE content — legitimate and required for a fresh entry (nothing exists to scope into), but on an EXISTING entry a missing marker is refused **400**, never a silent full replace. A deliberate full rewrite states that intent explicitly: `<1,-1>` resolves through the ordinary marker math to the same whole-content replacement, so the capability is available but cannot be selected by omission.
1279
+ - §edit-line-anchors An anchored EDIT resolves under {§line-anchors} and carries
1280
+ its endpoint checks as a core-private mutation precondition. Otherwise-valid
1281
+ zero/multiple matches and later precondition misses share {§edit-collision};
1282
+ malformed positions and schemes without textual EDIT scopes return 400 before
1283
+ handler invocation, while an upstream current-read failure preserves its
1284
+ status. The model-facing teaching recommends anchors for EDIT because this
1285
+ rejection is deliberate stale-target protection; parser support for anchors
1286
+ on observations does not imply the same recommendation.
1287
+ - §edit-collision Every standard entry EDIT lands by compare-and-swap against
1288
+ the exact channel content used to calculate it, including numeric-only EDITs.
1289
+ A concurrent creator that wins the resource identity or channel, an anchor
1290
+ that no longer identifies exactly one line, a selected endpoint neighborhood
1291
+ that changes before mutation, or a representation that changes in the final
1292
+ check/write gap returns the same neutral **409 `edit-collision`** and preserves
1293
+ the winner's content. Its public detail says only that EDIT collided with
1294
+ another change and directs the model to READ and retry; it does not assign
1295
+ fault or reveal which detection layer won. Concurrent correct workers are an
1296
+ ordinary cause. Core resolves anchors, scheme handlers receive only numeric
1297
+ coordinates, the shared entry mutation owner rechecks selected endpoint
1298
+ neighborhoods against its exact snapshot, and atomic identity/channel claims
1299
+ and storage predicates close the remaining races.
1235
1300
 
1236
1301
  A `file:///` member EDIT diverges from this immediate-write contract: it diffs against the entry snapshot (the body channel, never a fresh disk read) and **proposes** (202) a disk write that lands via a compare-and-swap on accept. See {§membership-edit-write-cas} and the proposal lifecycle {§proposal}. The marker-required rule above applies identically here — an existing file is never markerlessly replaced.
1237
1302
 
@@ -1239,25 +1304,44 @@ A `file:///` member EDIT diverges from this immediate-write contract: it diffs a
1239
1304
 
1240
1305
  AST: `{ op: "READ", target, body: null, signal: tags | null, lineMarker? }`.
1241
1306
 
1307
+ Matcher-bearing or path-glob READ syntax has already normalized to canonical
1308
+ FIND before dispatch under {§read-find-normalization}; core has no second READ
1309
+ selection or fan-out path.
1310
+
1242
1311
  - §read-read-content Returns channel content and mimetype.
1243
1312
  - §read-read-404 Returns 404 when the channel is absent.
1244
1313
  - §read-selection-projection READ applies `lineMarker` as text coordinates to one
1245
1314
  exact target under {§read-exact-target}. Markerless READ synthesizes
1246
1315
  `<1,16>`; `<1,-1>` explicitly selects all text. Successful positional reads
1247
1316
  carry the compact requested/returned extent and available total
1248
- ({§range-extent}). An invalid text region is 416.
1317
+ ({§range-extent}). Anchors resolve under {§line-anchors} before selection. An
1318
+ invalid text region is 416.
1319
+
1320
+ §log-item-tags **Tags classify durable log items.** Under {§log-tag-signal}, FIND, READ, EDIT, COPY,
1321
+ and MOVE strip any leading `+` from every signal term and add the resulting tag
1322
+ to the one log row created for that operation. The row receives its complete
1323
+ deduplicated set even when the operation fails or has no body; the signal never
1324
+ filters candidates, changes a resource, or persists on an entry. OPEN and FOLD
1325
+ use every unsigned signal term as an ALL-tags filter over existing log rows;
1326
+ their optional target and matcher intersect that set. They then strip and add
1327
+ each `+tag` and strip and remove each `-tag` on the exact selected rows while
1328
+ applying the requested visibility. Signed terms never select: a curation
1329
+ operation requires a target, matcher, or unsigned tag. Add and remove terms for
1330
+ the same tag conflict. Successful visibility and classification changes land as
1331
+ one curation event whose exact per-row deltas are durable. Engine policy may
1332
+ apply its separately specified diagnostic classifications, such as `overflow`.
1333
+ Every classification lives once in `log_tags`, is erased with its row, and is
1334
+ copied with log history on fork.
1249
1335
 
1250
1336
  ### §open-fold OPEN / FOLD
1251
1337
 
1252
1338
  AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: null }`.
1253
1339
 
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.
1340
+ OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). FOLD collapses a log row to its path; OPEN restores its ordinary packet projection, including any preview bound ({§body-projection}). Both select by target, matcher, and the symmetric ALL-tags filter, then apply the tag changes defined by {§log-item-tags}. The canonical full body remains available through READ of the log URI with `<1,-1>`. Non-destructive: rows and bodies persist. On any valid row, applying its current state again or targeting a bodyless row is a successful visibility no-op; classification changes still land. Malformed targets and nonexistent exact coordinates fail at their addressing boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1255
1341
 
1256
1342
  ### §jsonplurnk The Log's wire format
1257
1343
 
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}
1259
-
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.
1344
+ The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every content line begins with a numeric `N:` or anchored `@hash N:` coordinate prefix whose separator is one or more ASCII spaces, and its closing quote appears at column zero before either the object close or a following member. Source quotes, braces, fences, and headings cannot collide with either boundary because source text never occupies column zero after projection; source backticks therefore cannot form a CommonMark closing fence. The fixed opener keeps the packet prefix stable across content changes. The carve-out is localized to `body`, so the strip-parser recognizes `"body":"` followed by a newline, consumes one or more coordinate-prefixed lines, and replaces the raw multiline value with an escaped JSON string while preserving following members to recover strict JSON. The body shape is a strict three-state invariant: `"display":"none","body":""` for no body, `"display":"folded"` with the ordinary projection withheld, and `"display":"open","body":"\n<coordinate>...\n"` with it shown. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an OPEN bounded projection differs from the canonical body, it appends `"chunk":"showing <selected> of <complete>"` after `body`; otherwise it omits `chunk`. Complete-line extents use inclusive two-coordinate line regions. A cut inside a line uses four-coordinate, start-inclusive and end-exclusive regions with 1-based Unicode code-point columns. The row's `path` remains the canonical READ target. The block is data only - no prose leads the fence. `tokens` is the ruler-weight of the row's ordinary packet body: the room OPEN adds and FOLD saves. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page has a different weight. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/coordinate-prefixed bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body/display state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1261
1345
 
1262
1346
  ### §retrieval-packet-metadata READ/FIND packet metadata
1263
1347
 
@@ -1282,21 +1366,18 @@ and its internally resolved whole-line region. Exact READ retains only its
1282
1366
  region. A failed retrieval's Problem owns its range extension rather than
1283
1367
  repeating it at top level. Generic `tokens` always weighs the rendered body;
1284
1368
  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.
1369
+ that have no retrieval extent. FIND content weights follow {§jsonplurnk};
1370
+ ordinary bounded bodies expose their displayed and complete chunk extents there.
1287
1371
 
1288
1372
  ### §model-entry The model's own emission, mirrored back
1289
1373
 
1290
1374
  §model-entry-log-curation A model-emission log row is the model's **verbatim emission**, mirrored back so it can inspect and curate its own behavior. It is an actionless artifact: `op` is null, `attrs.kind="model_emission"` identifies the row, no target exists, `tx` is empty, and the emission lives in `rx.content`, typed `text/vnd.plurnk`. Its exact address is the undecorated three-part coordinate `log:///<L>/<T>/<S>` because no operation exists to append. An admitted emission is **always born FOLDED** (budget-neutral), line-numbered like all content, and OPEN/FOLD/KILL-able like any log row. Log-KILL clears the `writableBy` gate for the model (the DB-storage curation lever plurnk.md teaches; Log's handler surface — kill only — keeps every other mutating op at 501). The engine writes one after each admitted model turn. The invalid-emission recovery item under {§emission-admission} mirrors only the latest rejected response, is born FOLDED with `attrs.admission="rejected"`, and is projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
1291
1375
 
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.
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.
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.
1296
-
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}
1376
+ - §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with `## READ0 (worker:///docs/)`. A rendered operation row appends its canonical model-facing `/OP`, not a fourth resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive suffix is authoritative and a disagreement resolves 404. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ` deliberately filters the canonical suffix.
1377
+ - §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — OPEN/FOLD/KILL take a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}), like a folder-scoped FIND: `## FOLD0 (log:///1/2)` folds turn 1/2's rows. OPEN and FOLD may instead take only a tag filter ({§log-item-tags}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. A targetless operation without tags or a matcher is 400.
1378
+ - §log-curation-set-selection **Set selection, never positional curation** — target/glob, optional body matcher, and optional ALL-tags filter compose by intersection into the affected row set. OPEN and FOLD have no `<L>` marker and never paginate that set; FIND owns result pagination.
1298
1379
 
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.
1380
+ §fold-open-meta-operations **OPEN and FOLD are meta-operations — log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). Its exact selected target set, each target's pre-event visibility, and the classifications actually added and removed persist with that event; `matched: N` and the authored selector are not the database's sole effect evidence. The operation row, visibility changes, tag changes, and landed effects commit in one database statement. The emission also survives verbatim in its model-emission mirror. A **failed** OPEN/FOLD (bad target, matcher, or tag signal) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
1300
1381
 
1301
1382
  §kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its emission survives in its model-emission mirror. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match ≠ error but a malformed coordinate is) renders like any error.
1302
1383
 
@@ -1313,7 +1394,7 @@ secret detection.
1313
1394
  | Query and authored body | Preserved exactly; they are authored content and URI identity, not structurally identifiable credential slots. |
1314
1395
  | Parser failure | Preserves the structural diagnosis and source position without quoting request-metadata contents ({§path-request-metadata}). |
1315
1396
  | Client, fork, packet, and digest | Consume the stored projection; none owns a second redaction policy. |
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. |
1397
+ | Model-call evidence and model-emission mirror | `model_calls.response` under {§emission-admission} and the folded row under {§model-entry-log-curation} remain exact forensic evidence and are the explicit exception. |
1317
1398
 
1318
1399
  ### §copy COPY (engine-orchestrated)
1319
1400
 
@@ -1322,17 +1403,20 @@ body: ResourceSelection (destination), signal: tags | null }`.
1322
1403
 
1323
1404
  1. §copy-missing-source-404 Resolve source path, channel, and optional text scope; missing resource or
1324
1405
  channel is 404. A binary marker is not a byte channel and returns 415;
1325
- readable projections are ordinary text sources under {§membership-source-projection}.
1406
+ readable projections are ordinary text sources under
1407
+ {§membership-source-projection}. Source anchors resolve under
1408
+ {§line-anchors}.
1326
1409
  2. Resolve destination path, channel, and optional text scope. Source and
1327
- destination mimetypes must agree or the result is 415.
1410
+ destination mimetypes must agree or the result is 415. Destination anchors
1411
+ resolve independently under {§line-anchors}.
1328
1412
  3. A scoped destination must already exist and is mutated through the
1329
1413
  destination scheme's `editBatch`.
1330
1414
  4. An unscoped destination writes only its selected channel. Existing other
1331
1415
  channels survive.
1332
1416
  - §copy-conflict-409 Different content in that channel is 409.
1333
- - §copy-noop-304 Identical content with no new tag is 304.
1334
- 5. Only explicit `signal` tags are applied, additively, to the destination.
1335
- Source tags are never copied.
1417
+ - §copy-noop-304 Identical content is 304.
1418
+ 5. The signal classifies the COPY log item and never changes either resource
1419
+ ({§log-item-tags}).
1336
1420
 
1337
1421
  §copy-cross-scheme-copy The result is 201 for a new entry, 200 for a write, 304 for an exact no-op, or
1338
1422
  202 when the owning scheme requires proposal review. Same- and cross-scheme
@@ -1346,8 +1430,14 @@ body: ResourceSelection (destination), signal: tags | null }`.
1346
1430
  - §move-relocation-deletes-source MOVE first performs the destination mutation under {§copy}, then removes only
1347
1431
  the selected source region or channel. A whole-channel MOVE deletes the
1348
1432
  source entry only when that was its final channel.
1433
+ - §move-canonical-whole-source The canonical whole-content source scope
1434
+ `<1,-1>` resolves as a whole-channel selection for MOVE: it removes the
1435
+ selected channel and deletes the source entry when that was its final
1436
+ channel. Every other source scope remains regional even when it currently
1437
+ covers all available text; resource deletion is never inferred from extent.
1349
1438
  - A same-channel regional MOVE applies destination insertion and source
1350
- deletion in one same-snapshot `editBatch`; overlapping regions are 409.
1439
+ deletion in one same-snapshot `editBatch`; source and destination anchor
1440
+ preconditions compose against that snapshot, and overlapping regions are 409.
1351
1441
  - A cross-resource destination failure leaves the source untouched. A source
1352
1442
  failure after destination success is an explicit partial failure with
1353
1443
  `destinationWritten: true`. Proposal acceptance/rejection follows the same
@@ -1372,16 +1462,15 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
1372
1462
  identity-bearing: `https://example.com/page` queries
1373
1463
  `(https, /example.com/page)`, never `(https, /page)`.
1374
1464
  - §find-glob-filter-on-content `body` matcher operates on entry content (glob/regex/jsonpath/xpath), per `plurnk.md` "Pattern Filtering"; the path-glob lives in the (target), not the body.
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.
1376
- - §find-tag-filter-and-semantics `signal` is a tag filter; entries match if they have ALL listed tags.
1465
+ - §find-semantic-selection Every matcher operates only over the candidate set selected by `(target)`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies the ordinary FIND result scope. Markerless semantic FIND therefore uses the same `<1,16>` default as every other matcher. Integers retain FIND's positional contract: `<N>` selects result N and `<N,M>` selects the inclusive range. A leading decimal first applies a minimum cosine-similarity threshold; following integers select positions within that ranked threshold set. Thus `<0.7,10,20>` means threshold 0.7 followed by results 10 through 20, while `<0.7>` applies the threshold and the ordinary first-16 page.
1377
1466
  - §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
1378
1467
  - §find-result-projection **The authored target shape determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsTokenTotal, returnedItemsTokenTotal }`:
1379
1468
 
1380
1469
  | Target | Matcher body | `range.unit` | Result rows |
1381
1470
  |---|---|---|---|
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` |
1471
+ | exact | absent | `resource` | the one catalog channel group |
1472
+ | glob or folder | absent | `resource` | catalog channel groups |
1473
+ | glob or folder | present | `resource` | matching channel groups with `matchLocationCount` on `[0]` |
1385
1474
  | exact | present | `matchLocation` | flat `{ locator?, region? }` locations |
1386
1475
 
1387
1476
  A glob or folder remains resource mode when it resolves to one path. An exact
@@ -1393,13 +1482,20 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
1393
1482
 
1394
1483
  Inside `FindResult`, `matchingPathCount` and `matchLocationCount` describe the
1395
1484
  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:
1399
- `{ path, stream?, tags?, channels: { <uri>: { mimetype, tokens, lines } } }`.
1485
+ {§retrieval-packet-metadata}. `path` is reserved for resource or channel identity;
1486
+ broad results never nest locations, and exact location rows never repeat the
1487
+ resource path. A **body-less** FIND is the **catalog**. Its outer result array
1488
+ contains one nonempty, flat channel array per resource. Element `[0]` is always
1489
+ the default channel and carries the bare resource path; later elements carry
1490
+ their complete `path#channel` addresses. Each channel is
1491
+ `{ path, mimetype, tokens, lines, parseIssues? }`; `parseIssues` is the
1492
+ positive-only advisory projection of `{§mimetype-parse-issues}` for the exact
1493
+ body derivation under `{§scheme-catalog-parse-issues}`. Resource-level `stream` and broad-match
1494
+ `matchLocationCount` live only on `[0]`. A single-channel resource is therefore
1495
+ a one-element array, with no path-owning wrapper or duplicated channel map.
1400
1496
  A terminal single-star path scope is a one-level map: direct entries retain
1401
- that shape, while deeper first-segment directories collapse to
1402
- `{ path: "dir/**", items, tokens }`, where the selector and both aggregates
1497
+ that shape, while deeper first-segment directories collapse to the one-element
1498
+ group `[{ path: "dir/**", items, tokens }]`, where the selector and both aggregates
1403
1499
  describe the exact recursive subtree. Scope summaries are navigation
1404
1500
  metadata, not resources. Markerless FIND returns positions 1–16 in the
1405
1501
  selected unit; `<N,M>` selects an inclusive page and `<1,-1>` explicitly
@@ -1430,9 +1526,9 @@ AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, signal: nu
1430
1526
  |---|---|---|---|
1431
1527
  | **102** continue | next turn | next turn | next turn |
1432
1528
  | **200** done | **resolved** — terminal, loop ends | **refused** — Premature-Terminate (KILL to abandon, or wait) | **refused** — forced next turn to see the result |
1433
- | **202** wait | **resolves like 200** a wait on zero things is satisfied; `<-1>+∅` is a bid to hang the agent, folded to done, never honored | **block on the join** — the loop sleeps (`<T>`/`<-1>` bound it, `<P>` polls); its work's conclusion **reawakens the same loop**, prompt intact ({§worker-lifecycle-child-wake}, {§worker-lifecycle-wake-liveness}) | resolves next turn (≈ continue) |
1529
+ | **202** wait | **resolves like 200**, unless this turn successfully FOLDed an empty wait is satisfied, while FOLD continues into the curated next packet | **block on the join** — the loop sleeps (`<T>`/`<-1>` bound it, `<P>` polls); its work's conclusion **reawakens the same loop**, prompt intact ({§worker-lifecycle-child-wake}, {§worker-lifecycle-wake-liveness}) | resolves next turn (≈ continue) |
1434
1530
 
1435
- §wait-obligation-matrix **499** gives up regardless of obligations and cancels the unresolved descendant scope — the model's one self-decided failure ({§state-terms}). The surface is small on purpose. The **one** non-obvious cell is **200 with an obligation in flight** — a contradiction (you claimed done while you owe work), which the engine holds you to via Premature-Terminate below. A child join is bounded by the child's terminal transition; an external stream may carry an explicit `<T,P>` policy.
1531
+ §wait-obligation-matrix **499** gives up regardless of obligations and cancels the unresolved descendant scope — the model's one self-decided failure ({§state-terms}). The surface is small on purpose. The **one** non-obvious cell is **200 with an obligation in flight** — a contradiction (you claimed done while you owe work), which the engine holds you to via Premature-Terminate below. A child join is bounded by the child's terminal transition; an external stream may carry an explicit `<T,P>` policy. A successful same-turn FOLD is synchronous housekeeping, so it does not block an explicit `200`; with `202`, it instead continues as `102` because its context effect is useful only in the curated next packet.
1436
1532
 
1437
1533
  §loop-terminal-authorship **Terminal authorship is explicit when external.**
1438
1534
 
@@ -1453,7 +1549,7 @@ the loop continue; repeated offenses terminate through the engine's 500.
1453
1549
  | Idle turn | An engine-rail error row with the corrective disposition | One strike |
1454
1550
  | Refused disposition | The final SEND's 409 row with its exact Problem Detail | One strike |
1455
1551
 
1456
- - §send-idle-turn **Idle turn** — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with 200. If you're waiting on a child or stream you spawned, SEND[202] to block on it — a 202 with nothing to wait on simply concludes."*
1552
+ - §send-idle-turn **Idle turn** — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with `## SEND0 [200]`. If you're waiting on a child or stream you spawned, use `## SEND0 [202]` to block on it — a 202 with nothing to wait on simply concludes."* A successful same-turn FOLD is the exception: its `202` continues without a strike so the curated packet can support the next reasoning turn.
1457
1553
  - §send-premature-terminate **Premature terminate — the pending set.**
1458
1554
  Completion is gated by one rule: *nothing pending may be silently
1459
1555
  discarded*. Pending work has two states: **live obligations** (open
@@ -1466,68 +1562,76 @@ the loop continue; repeated offenses terminate through the engine's 500.
1466
1562
  retrieval-only refusal. The pending kind changes the corrective message, not
1467
1563
  rail accounting. `[499]` deliberately abandons regardless.
1468
1564
  - §send-undelivered-child-term **Completion is not delivery.** A result becomes
1469
- observed only after crossing a packet boundary. `SEND[202]` parks only on
1565
+ observed only after crossing a packet boundary. SEND signal `202` parks only on
1470
1566
  live obligations. If work has completed but is unobserved, it continues
1471
1567
  directly to the next packet because the wake edge has already fired; only a
1472
- genuinely empty set resolves immediately like `[200]`.
1473
- - §send-300-choices **SEND[300] is an operator question - a PROPOSAL using the same stop-the-world system as file edits.** Enablement cascades: `PLURNK_QUESTIONS=0` is a servicewide ceiling; otherwise the client affirmatively requests per workspace (`settings.questions: true` at workspace creation), which ALSO injects the required `questions.md` teaching - capability and teaching gate as one ({§teaching-corpus}). An enabled workspace fails doc materialization with the read cause if that source is broken; a disabled workspace does not consume it. Enabled: the `;`-delimited body parses leniently (first segment the question, the rest choices; zero choices = an open question - never malformed), and the ask raises a proposal: dispatch stops the world, `loop/proposal` carries `{question, choices}` in attrs, and the client's accepted proposal body delivers the ANSWER - written into the ask's own model-facing rx (`{"status":200,"body":...}`), read next packet. Reject/timeout resolve through the standard {§proposal} semantics; the turn records a continue either way (never a 300 terminal), and the loop simply proceeds. Loop auto never auto-answers a question - it exists precisely to stop the world for a human, and the workspace opted in. Disabled: refused 409 with a self-decide steer, never a park into the void.
1568
+ genuinely empty set with no successful same-turn FOLD resolves immediately like `[200]`.
1569
+ - §send-300-choices **SEND signal `300` is an operator question - a PROPOSAL using the same stop-the-world system as file edits.** Enablement cascades: `PLURNK_QUESTIONS=0` is a servicewide ceiling; otherwise the client affirmatively requests per workspace (`settings.questions: true` at workspace creation), which ALSO injects the required `questions.md` teaching - capability and teaching gate as one ({§teaching-corpus}). An enabled workspace fails doc materialization with the read cause if that source is broken; a disabled workspace does not consume it. Enabled: the `;`-delimited body parses leniently (first segment the question, the rest choices; zero choices = an open question - never malformed), and the ask raises a proposal: dispatch stops the world, `loop/proposal` carries `{question, choices}` in attrs, and the client's accepted proposal body delivers the ANSWER - written into the ask's own model-facing rx (`{"status":200,"body":...}`), read next packet. Reject/timeout resolve through the standard {§proposal} semantics; the turn records a continue either way (never a 300 terminal), and the loop simply proceeds. Loop auto never auto-answers a question - it exists precisely to stop the world for a human, and the workspace opted in. Disabled: refused 409 with a self-decide steer, never a park into the void.
1474
1570
 
1475
1571
  ### §exec EXEC
1476
1572
 
1477
- AST: `{ op: "EXEC", target (optional input source, program, or cwd), body: string | null (command), signal: string | null (runtime tag), lineMarker (timeout/poll) }`.
1573
+ AST: `{ op: "EXEC", target (optional runtime-specific target), body: string | null (runtime-specific input), signal: string | null (runtime tag), lineMarker (timeout/poll) }`.
1478
1574
 
1479
- §exec-target-routing Engine routes unconditionally to the `exec` scheme and
1480
- canonicalizes `(target)` before effect admission. With no directory override,
1575
+ §exec-target-routing Engine routes unconditionally to the `exec` scheme,
1576
+ resolves the runtime first, and enforces that runtime's required
1577
+ {§executor-invocation} declaration before effect admission. Core owns target
1578
+ realization; neither filesystem type nor body presence may invent a target role
1579
+ the selected runtime did not declare. With no declared directory override,
1481
1580
  `cwd` is the workspace's `project_root`, where the File scheme writes — never
1482
- the daemon's own cwd. A non-file scheme address is an eligible content source
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.
1487
-
1488
- | Authored target | Body | Canonical effect target | Accepted executor realization |
1489
- | ------------------------------------- | --------- | ----------------------- | ----------------------------------------------------- |
1490
- | Absent | Non-empty | `null` | Body is the command; target is absent. |
1491
- | Local/file directory | Non-empty | `null` | Directory becomes `cwd`; target is absent. |
1492
- | Local/file file or stat miss | Any | Authored local path | Path is the program/data target; body is its input. |
1493
- | Readable data-scheme address | Empty | `null` | Selected READ content becomes the command. |
1494
- | Readable data-scheme address | Non-empty | Authored address | Selected READ content becomes a local target. |
1495
-
1496
- §exec-source-temporary A non-empty-body data-scheme source is materialized into
1497
- one core-owned temporary file after acceptance. The file lives through the
1498
- executor run and core removes it after the subscription's terminal result has
1499
- settled. A removal failure is reported to daemon diagnostics with its complete
1500
- cause; it cannot rewrite the execution result, stream state, or completion
1501
- wake.
1502
-
1503
- Loop-flag authority follows the same target classification:
1504
-
1505
- | Target class | Schemes that must be active |
1506
- | ------------------------------ | ---------------------------------------- |
1507
- | Absent, local, or `file://` | `exec` |
1508
- | Non-file scheme address | `exec` and the addressed source scheme |
1509
-
1510
- A stat miss means exactly `ENOENT` and takes the file arm so the runtime reports
1511
- its own not-found rather than dispatch returning 400. Any other stat failure
1512
- stops target classification before effect admission with a core-owned 500
1513
- Problem: its bounded diagnostic states the occurrence-specific cause and daemon
1514
- diagnostics retain the complete error. An empty body is legal for a local file
1515
- or scheme command source; it remains a 400 with no target or a directory target.
1516
- For a scheme-data target, the authored address is an opaque target-present
1517
- identity: the executor neither resolves it nor sees it during `run()`; core
1518
- materializes the selected content only after acceptance and supplies that local
1519
- path.
1581
+ the daemon's own cwd.
1582
+
1583
+ | Declared target kind | Authored target | Canonical effect target | Executor realization |
1584
+ | -------------------- | --------------------------------------- | ----------------------- | --------------------------------------------------------- |
1585
+ | Omitted | Any present target | — | Refuse 400 before admission. |
1586
+ | `literal` | Any target | Complete authored string | Preserve that exact string; perform no stat or scheme read. |
1587
+ | `path` | Local or `file://` path | Local path | Pass the path directly. |
1588
+ | `path` | Non-file address | | Refuse 400 before admission. |
1589
+ | `resource` | Local or `file://` path | Local path | Pass the path directly. |
1590
+ | `resource` | Non-file data-scheme address | Complete authored address | Resolve one exact READ after acceptance and pass its temporary local file. |
1591
+
1592
+ A local directory becomes `cwd` with an absent executor target only when the
1593
+ runtime declaration explicitly sets `target.directory: "cwd"`; otherwise it
1594
+ remains the target. Core stats only for that declared rule. `ENOENT` remains a
1595
+ target so the runtime reports its own not-found. Any other stat failure stops
1596
+ before effect admission with a core-owned 500 Problem whose bounded diagnostic
1597
+ states the occurrence-specific cause while daemon diagnostics retain the
1598
+ complete error.
1599
+
1600
+ Body and target requirements come from the same runtime declaration. A runtime
1601
+ with no target declaration refuses a target; required body or target fields are
1602
+ enforced independently; every EXEC requires at least one of them; and an
1603
+ `exclusive` declaration refuses an invocation containing both. A target retains
1604
+ its one declared role whether the body is empty or non-empty. Runtime selection,
1605
+ target validation, and body/target relation failures therefore occur before
1606
+ effect classification or proposal creation.
1607
+
1608
+ §exec-source-temporary A non-file `resource` target is materialized into one
1609
+ core-owned temporary file after acceptance. Core reparses the complete authored
1610
+ address and resolves one exact `<1,-1>` READ through
1611
+ {§universal-read-composition}; internal source consumption never borrows the
1612
+ model-facing 16-line preview. The file lives through the executor run and core
1613
+ removes it after the subscription's terminal result has settled. A removal
1614
+ failure is reported to daemon diagnostics with its complete cause; it cannot
1615
+ rewrite the execution result, stream state, or completion wake.
1616
+
1617
+ Loop-flag authority follows the selected runtime's declaration:
1618
+
1619
+ | Target realization | Schemes that must be active |
1620
+ | ------------------------------------------------------- | -------------------------------------- |
1621
+ | Absent, `literal`, local `path`, or local `resource` | `exec` |
1622
+ | Non-file `resource` | `exec` and the addressed source scheme |
1623
+
1520
1624
  Worker and runtime-stream authorities, query, fragment, request metadata, and
1521
- every other address component therefore retain their owning READ semantics. A
1522
- failed source READ is preserved as the proposal-application failure. A
1523
- successful READ with no string representation is refused 422; `""` remains a
1524
- present representation, although it cannot by itself become an executable
1525
- command.
1625
+ every other component of a `resource` address retain their owning READ
1626
+ semantics. A failed source READ is preserved as the proposal-application
1627
+ failure. A successful READ with no string representation is refused 422; an
1628
+ empty string remains a present representation and is materialized faithfully.
1526
1629
 
1527
- Core calls `effect()` once against this canonical target, without command text,
1528
- stores the resulting fact with the invocation, and reuses it unchanged for
1529
- proposal policy, application, stream registration, and effect-qualified hold
1530
- policy. The post-acceptance materialization path never triggers reclassification.
1630
+ Core calls `effect()` once against the canonical target shown above, without
1631
+ body text, stores the resulting fact with the invocation, and reuses it
1632
+ unchanged for proposal policy, application, stream registration, and
1633
+ effect-qualified hold policy. The post-acceptance materialization path never
1634
+ triggers reclassification.
1531
1635
 
1532
1636
  §exec-registry-resolves The runtime slot (`signal`) selects an executor,
1533
1637
  resolved against the boot-time `ExecutorRegistry`: siblings are discovered and
@@ -1538,7 +1642,7 @@ put a complete command in bare `EXEC`; they are never reinterpreted as shell
1538
1642
  command words. An unavailable runtime is also 501 and carries the probe
1539
1643
  `detail`.
1540
1644
 
1541
- Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor tags merely because they are executables; they are complete shell commands in bare `EXEC` or `EXEC[sh]`. Registered tags exist only for tools that own a distinct body, target, or output contract. {§exec-registry-resolves}
1645
+ Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor tags merely because they are executables; they are complete shell commands under `## EXEC0` or `## EXEC0 [sh]`. Registered tags exist only for tools that own a distinct body, target, or output contract. {§exec-registry-resolves}
1542
1646
 
1543
1647
  **Timeout and poll — `<T,P>` on the `<L>` slot (grammar 0.74.20).** EXEC
1544
1648
  repurposes the line-marker slot as `<timeout, poll>` in **seconds**, the same
@@ -1554,7 +1658,7 @@ before the turn's own spawns, so it never survives into the subsequent turn;
1554
1658
  its terminal output surfaces born-OPEN like any close ({§exec-stream}).
1555
1659
 
1556
1660
  §exec-poll `P` (`mark[1]`) is the **poll cadence**, stored on the subscription.
1557
- While the loop is blocked on a `SEND[202]` wait for that stream, the daemon arms
1661
+ While the loop is blocked on a SEND signal `202` wait for that stream, the daemon arms
1558
1662
  a per-worker timer for the tightest open poll cadence and resumes the blocked
1559
1663
  loop every P seconds, floored by `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS` so it cannot tick
1560
1664
  faster than the optimistic settlement scale, to inspect progress. It does **nothing while the
@@ -1603,9 +1707,9 @@ observation is born OPEN; a terminal state with no newly publishable body still
1603
1707
  produces one conclusion row. Every READ then obeys {§body-projection} and
1604
1708
  therefore renders its selected result complete. A stream that closes before a
1605
1709
  same-turn wait remains pending until this terminal READ crosses the next packet
1606
- boundary. The EXEC row separately records the command.
1710
+ boundary. The EXEC row separately records the authored invocation.
1607
1711
 
1608
- `KILL(<runtime>:///<loop>/<turn>/<seq>)` cancels an active subprocess via
1712
+ `## KILL0 (<runtime>:///<loop>/<turn>/<seq>)` cancels an active subprocess via
1609
1713
  the subscription registry's stored controller. A terminal stream is immutable:
1610
1714
  499 returns 410 (already killed), every other terminal status returns an RFC
1611
1715
  9457 409 Problem carrying `terminalStatus`, and an unknown address returns 404.
@@ -1613,8 +1717,8 @@ The runtime scheme participates in the durable lookup; a completed `sh:///`
1613
1717
  stream cannot fall through an internal `exec`-only query. {§stream-control}
1614
1718
 
1615
1719
  §exec-env-scoped **Scoped environment.** An EXEC subprocess inherits the *project's* environment — its `.env`, the standard shell vars — so the model's commands run as the project expects; but never plurnk's own secrets: the provider API keys and `PLURNK_*` config are stripped before the spawn, so a model-executed command can't `printenv` the engine's keys. The service owns the scoping policy (the denylist); the executor spawns with the env it is handed.
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.
1720
+ - §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits EXEC followed by SEND signal `102` as ever; the wake-shaped world simply arrives one packet sooner. It extends selected runtimes beyond the ordinary {§worker-optimistic-settlement} cap before the next packet assembles. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
1721
+ - §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry, then journals ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `tokens` = the content's count, and `attrs.kind="entry_materialized"`. The requested tags classify that journal row under {§log-item-tags}; they never become resource metadata or duplicate into attrs. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked WebFetcher and accepts its model-facing body and available source/evidence channels {§html-materialization}. Generic public HTML follows the same origin-Markdown, configured Tavily, and local-projection routes as exact HTTP acquisition. A failed acquisition, body-production failure, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype) and grants no provider authority. **No page body ever rides a packet**; the announcement is the folded row's path, weight, and log classifications, and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
1618
1722
 
1619
1723
  ### §proposal The proposal lifecycle
1620
1724
 
@@ -1630,7 +1734,7 @@ stream cannot fall through an internal `exec`-only query. {§stream-control}
1630
1734
 
1631
1735
  | decision | state | `status_rx` | default outcome | effect |
1632
1736
  |---------------------------------|---|---|---|---|
1633
- | §proposal-accept-applies accept | `resolved` | 200 | — | runs the scheme's **`applyResolution`** — the real side effect (disk write, exec spawn). A failing apply (≥400) downgrades to reject, carrying the apply's own outcome — e.g. a member EDIT's `write_conflict` from its write-back compare-and-swap ({§membership-edit-write-cas}) — or `apply_failed` when it names none. |
1737
+ | §proposal-accept-applies accept | `resolved` | 200 | — | runs the scheme's **`applyResolution`** — the real side effect (disk write, exec spawn). A failing apply (≥400) downgrades to reject, carrying the apply's own outcome — e.g. a member EDIT's `edit_collision` from its write-back compare-and-swap ({§membership-edit-write-cas}) — or `apply_failed` when it names none. |
1634
1738
  | §proposal-reject-fails reject | `failed` | 400 | `rejected` | none — the action did not occur. |
1635
1739
  | §proposal-cancel-aborts cancel | `cancelled` | 499 | `loop_aborted` | none — the loop is abandoning. |
1636
1740
 
@@ -1678,7 +1782,7 @@ Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination, but
1678
1782
 
1679
1783
  ### §subscriptions Subscriptions
1680
1784
 
1681
- §subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. `SEND[499]`, worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation hook or database access is part of the plugin contract.
1785
+ §subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. SEND signal `499`, worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation hook or database access is part of the plugin contract.
1682
1786
 
1683
1787
  The durable row is lifecycle evidence and the lookup key, not a serialized callback. `subscriptions.open()` establishes both halves before yielding a composed `StreamSubscription`: an `AbortSignal` whose fused `notifyChunk` and terminal `close` methods are safe to retain without the operation's general `SchemeCtx`. `close(result, summary?)` validates and persists the exact universal operation result, settles channel state, closes the durable row, wakes the worker when appropriate, and unregisters the live handle. `close_status` is a constrained relational projection of `close_result.status`, never an independent result. A durable open row without a live handle is an explicit lifecycle failure, never a fabricated cancellation success. Channel state ({§channel-state}) + log entries ({§no-chunk-rows}) carry lifecycle.
1684
1788
 
@@ -1701,12 +1805,13 @@ Model sees lifecycle events in the `log` section per turn.
1701
1805
 
1702
1806
  ### §deep-slices Deep slices on demand
1703
1807
 
1704
- `<<READ(https://feed.example/x#body)<N-M>:…:READ` pulls a slice into a log row when the model wants a specific line-range of an SSE stream.
1808
+ `## READ0 (https://feed.example/x#body) <N-M>` pulls a slice into a log row when the model wants a specific line-range of an SSE stream.
1705
1809
 
1706
- ### §stream-control SEND for stream control
1810
+ ### §stream-control Stream control and writes
1707
1811
 
1708
- - **Cancel:** `<<SEND[499](https://feed.example/x)::SEND` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
1709
- - **Write:** `<<SEND[200](wss://feed/x):body:SEND` pipes body into active connection (WS, exec stdin, etc.).
1812
+ - **Cancel:** `## SEND0 [499] (https://feed.example/x)` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
1813
+ - **WebSocket write:** `## EDIT0 (wss://feed/x)` or `## SEND0 [200] (wss://feed/x)` with a body sends one whole text frame through the active owner. SEND can follow the opening READ in the same turn; EDIT runs before READ ({§op-mode-phases}) and therefore addresses an owner already open at turn start.
1814
+ - **Other stream write:** `## SEND0 [200] (…)` remains scheme-defined, including exec stdin.
1710
1815
 
1711
1816
  ### §stream-constraints Engine constraints
1712
1817
 
@@ -1747,14 +1852,14 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
1747
1852
  **Lives in SQL:**
1748
1853
  - Render queries — log assembly + the manifest catalog.
1749
1854
  - Cross-scope path collision (CHECK/trigger → 409).
1750
- - Cost rollups (denormalized USD; atomic on turn close).
1855
+ - Logical model-call identity plus cardinal physical provider-request lifecycle and immutable settlement constraints.
1751
1856
  - Sequence number issuance (1-based per grammar).
1752
1857
  - Entry-vs-log integrity.
1753
1858
 
1754
1859
  **Lives in TS:**
1755
1860
  - Status-bubble rules (`turn.status` → `loop.status` → `worker.status` → `workspace.status`). Engine UPDATEs explicitly; CHECK constraints enforce; triggers fight branching state machines.
1756
1861
  - Tokenization (provider-bound; hot-swap re-tokenizes per {§tokenomics}).
1757
- - Provider dispatch + response normalization.
1862
+ - Provider dispatch, request-accounting validation, and exact-decimal aggregate projection through the shared contracts-owned path.
1758
1863
  - Scheme-handler invocation (connections, subprocesses, fetch).
1759
1864
  - Plugin loading ({§plugin-discovery}).
1760
1865
  - Stream AbortController lifecycle.
@@ -1838,7 +1943,7 @@ scheme. External schemes are discovered through
1838
1943
  dispatcher contract.
1839
1944
 
1840
1945
  The executor registry discovers installed runtimes, probes availability, and
1841
- routes `EXEC[<runtime>]`; core contributes orchestration and the output-scheme
1946
+ routes `## EXEC0 [<runtime>]`; core contributes orchestration and the output-scheme
1842
1947
  adapter, not runtime implementations. Optional and third-party leaves extend
1843
1948
  each family by installation and discovery; they never require a framework or
1844
1949
  service manifest edit.
@@ -1860,8 +1965,8 @@ service manifest edit.
1860
1965
 
1861
1966
  - Channel state (`static`/`active`/`closed`/`errored`) — persisted channel metadata owned by core and exposed through the schemes capability contract ({§channel-state}).
1862
1967
  - Backpressure caps — none ({§stream-constraints}).
1863
- - Stream cancel — `SEND[499]` ({§stream-control}).
1864
- - Delete — `KILL` (entry-KILL, the canonical delete, {§move}); `SEND[410]` also deletes as a side-effect ({§send-dispatch}).
1968
+ - Stream cancel — SEND signal `499` ({§stream-control}).
1969
+ - Delete — `KILL` (entry-KILL, the canonical delete, {§move}); SEND signal `410` also deletes as a side-effect ({§send-dispatch}).
1865
1970
  - §loop-flags-effective-read Per-loop flags — `loops.flags` persists a partial JSON object; every runtime policy read expands it over contracts-owned `DEFAULT_LOOP_FLAGS` and validates the complete `LoopFlags` before use. Missing rows or invalid values fail with the owning loop coordinate and cause. Raw archival copies and forensic rendering do not interpret policy.
1866
1971
  - Default-channel wire rendering — {§channel-selection}.
1867
1972
 
@@ -1896,10 +2001,13 @@ Model selection: separate alias cascade in `ProviderRegistry` ({§provider-insta
1896
2001
  | `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts cumulatively across every `202` park/resume. |
1897
2002
  | `PLURNK_SERVICE_MAX_COMMANDS` | `-1` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. PLAN and the final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
1898
2003
  | §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | `86400000` | ms wall-clock budget for a single core loop: expiry aborts the loop signal mid-flight (a stuck `generate` included) and the loop terminates `504 loop_timeout` — a legible engine terminal, kin to the exec `<T>` reap's 504 ({§exec-timeout}). |
1899
- | `PLURNK_SERVICE_MAX_STRIKES` | `3` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
2004
+ | `PLURNK_SERVICE_MAX_STRIKES` | `6` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
1900
2005
  | `PLURNK_SERVICE_EMISSION_ATTEMPTS` | `3` | Completed provider responses allowed beneath one engine turn before an untrustworthy model-turn frame exhausts admission. Bounded interior operation errors are admitted and do not spend this budget. Consecutive exhaustion after the one informed recovery turn terminates independently of strikes. |
1901
2006
  | `PLURNK_SERVICE_PREVIEW_LINES` | `16` | Maximum lines in an ordinary bounded log-body projection ({§body-projection}). |
1902
- | `PLURNK_SERVICE_PREVIEW_CHARS` | `2560` | Maximum characters in an ordinary bounded log-body projection; independently contains single-line bodies ({§body-projection}). |
2007
+ | `PLURNK_SERVICE_PREVIEW_CHARS` | `2560` | Maximum Unicode code points in an ordinary bounded log-body projection, with CRLF treated as one indivisible separator; independently contains single-line bodies ({§body-projection}). |
2008
+ | `PLURNK_SERVICE_PROMPT_PROJECTION` | `25%` | Aggregate ruler-weight share of the enforced packet budget available to automatic prompt-body projection ({§prompt-projection}); alias-scoped overrides are supported. |
2009
+ | `PLURNK_SERVICE_LINE_ANCHOR_CONTEXT_LINES` | `2` | Complete neighboring lines hashed on each side of a model-facing line anchor ({§line-anchors}). |
2010
+ | `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | `2` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
1903
2011
  | `PLURNK_SERVICE_MIN_CYCLES` | `3` | Min repetitions before cycle detection fires ({§engine-rails}). |
1904
2012
  | `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | `4` | Max period length cycle detection examines ({§engine-rails}). |
1905
2013
  | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
@@ -1927,14 +2035,14 @@ template both ways: every `PLURNK_SERVICE_*` the service reads has a
1927
2035
  declared `PLURNK_SERVICE_*` is read. A half-landed rename therefore fails a test
1928
2036
  instead of a user's boot, and a dead knob cannot ship.
1929
2037
 
1930
- §operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to gate-wide service posture: semantic search enabled, complete catalog orientation, automatic Git membership when the operator ceiling permits Git, and ambient operator-file docs/packet notes cleared. Configuration with a narrower or variable owner stays outside it:
2038
+ §operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to the safe default model plus gate-wide service posture: Turboderp, semantic search enabled, complete catalog orientation, automatic Git membership when the operator ceiling permits Git, and ambient operator-file docs/packet notes cleared. Configuration with a narrower or variable owner stays outside it:
1931
2039
 
1932
2040
  | Owner | Configuration |
1933
2041
  |---|---|
1934
- | `.env.test` | Universal real-model gate posture only; no aliases, routes, secrets, model tuning, or cost/sandbox ceilings. |
2042
+ | `.env.test` | Safe default model selection and universal real-model gate posture; no alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
1935
2043
  | Live/demo scripts | The repository personality path and runner topology. |
1936
2044
  | Benchlets | Their snapshotted policy, workspace restrictions, and task-specific exceptions; direct env wins over the profile. |
1937
- | Operator env/shell | Model selection, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
2045
+ | Operator env/shell | Model alias declarations and explicit selection overrides, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
1938
2046
  | `test/setup.ts` | Mock-only alias, envelope, resource, storage, and isolation fixtures; unit/integration never consume the real-model profile. |
1939
2047
 
1940
2048
  The profile does not repeat `NODE_OPTIONS`: runner selection belongs to the invoking command, and a process-global Node option would leak into the daemon and its children. Hard ceilings such as max turns, max commands, and Git denial remain operator-owned; harnesses bound paid experiments through their per-call contract and never widen a configured ceiling here.
@@ -2130,13 +2238,13 @@ loop with a conflicting selection fails before work is accepted. Provider
2130
2238
  instances are cached; no resume path substitutes a boot default for missing or
2131
2239
  malformed durable selection.
2132
2240
 
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
2241
+ §methods-loop-run-child-provider **Child-provider selection is one durable
2242
+ subcall policy.** Optional `childModel` (client-resolved `<provider>/<model>`, wins) or
2243
+ `childAlias` selects the provider for every WORK/FORK descendant and BARE inference; omitted uses
2136
2244
  `PLURNK_MODEL_CHILD`, while explicit `childAlias: null` means inherit. Core
2137
2245
  persists the resolved policy on each loop. A child runs on that provider and
2138
2246
  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
2247
+ remains inherit. BARE consumes the selection without spawning a child. Packet admission is unchanged: a smaller WORK is valid when
2140
2248
  its packet fits, and an oversized inherited FORK terminates through the ordinary
2141
2249
  child-loop result without preflight assembly or provider fallback.
2142
2250
 
@@ -2147,21 +2255,23 @@ coordinate without fetching all rows and matching locally.
2147
2255
 
2148
2256
  §methods-log-entry-wire **Log entry wire fidelity.** `readLog` and `log/entry`
2149
2257
  preserve causal `source` and parse the row's JSON `attrs` into structured data;
2150
- client interfaces do not reconstruct either field from operation or origin.
2258
+ they also project the row's complete sorted `tags` classification. Client
2259
+ interfaces do not reconstruct these fields from operation or origin.
2151
2260
 
2152
2261
  §op-look **LOOK ownership.** A client-interface module owns the public LOOK
2153
2262
  spelling and grammar parsing. It rewrites a valid LOOK statement to READ and
2154
2263
  hands the AST to core's `look`; core owns the full resolver and the no-log
2155
2264
  invariant. The internal closed, rowless observation segment supplies an honest
2156
2265
  numeric loop coordinate for relative `log:///` addressing without leaving
2157
- active lifecycle behind.
2266
+ active lifecycle behind. LOOK text anchors resolve through the same
2267
+ {§line-anchors} path as READ.
2158
2268
 
2159
2269
  ### §notifications Core events
2160
2270
 
2161
2271
  | Event | Payload | When fired |
2162
2272
  |--------------------------------------------------------------|---------|------------|
2163
2273
  | §notifications-log-entry-notify `log/entry` | `{ entry: LogEntry }` | A `log_entries` row is committed. |
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. |
2274
+ | §notifications-loop-terminated `loop/terminated` | `{ workerId, loopId, result, hitMaxTurns, turnIds, usage: { accounting, contextTokens, promptBudget, meta }, attributions }` | One loop reaches a terminal state. `result` is the exact universal operation result, including its RFC 9457 Problem Details on failure. `accounting` is the loop's contracts-owned {§provider-accounting}; `contextTokens` and `promptBudget` are the latest-turn gauge pair, and `meta` is that turn's opaque provider bag. `attributions` is the sorted union of exact provider-request evidence ({§attribution}), separate from accounting. Worker and loop are an inseparable owning coordinate. |
2165
2275
  | §notifications-loop-proposal `loop/proposal` | contracts-owned `ProposalProjection` | Dispatch pauses on a durable 202 proposal. `disposition` is the sole authority for whether a client presents review UI; live and reconnect share {§proposal-projection}. |
2166
2276
  | §notifications-workspace-created `workspace/created` | `{ id, name, projectRoot }` | A workspace is created. This is the only current global event. |
2167
2277
  | §notifications-workspace-branch-batch `workspace/branch-batch` | Branch-batch lifecycle payload | A branch batch enters queued, running, completed, failed, or recovery-required state. |
@@ -2235,12 +2345,12 @@ Conditional absence never reorders the surviving default sections.
2235
2345
  | Order | Slot | Section | Wire contract |
2236
2346
  |------:|:-------|:----------------------|:--------------|
2237
2347
  | 1 | system | `definition` | Framework definition; leads the most stable prefix. |
2238
- | 2 | system | `tools` | Executable capability sheet for this loop. |
2239
- | 3 | system | `optional-operations` | Present only when optional operations are enabled. |
2240
- | 4 | system | `schemes` | Active scheme catalogue. |
2241
- | 5 | system | `inject` | Present only when operator notes are configured. |
2242
- | 6 | system | `system-policy` | Operator policy; empty content is omitted on the wire. |
2243
- | 7 | system | `project-policy` | Project policy; empty content is omitted on the wire. |
2348
+ | 2 | system | `system-policy` | Operator policy; empty content is omitted on the wire. |
2349
+ | 3 | system | `project-policy` | Project policy; empty content is omitted on the wire. |
2350
+ | 4 | system | `tools` | Executable capability sheet for this loop. |
2351
+ | 5 | system | `optional-operations` | Present only when optional operations are enabled. |
2352
+ | 6 | system | `schemes` | Active resource catalogue. |
2353
+ | 7 | system | `inject` | Present only when operator notes are configured. |
2244
2354
  | 8 | user | `log` | Append-mostly model-visible history. |
2245
2355
  | 9 | user | `child-streams` | Per-turn status; empty content is omitted. |
2246
2356
  | 10 | user | `child-workers` | Per-turn status; empty content is omitted. |
@@ -2251,8 +2361,8 @@ Conditional absence never reorders the surviving default sections.
2251
2361
  | 15 | user | `prompt` | Current prompt-entry pointers. |
2252
2362
 
2253
2363
  The order favors prefix-cache locality where semantics permit: the definition
2254
- leads capability and privileged policy, while the append-mostly log leads the
2255
- volatile user-status clump. It does **not** claim that every system byte is
2364
+ and privileged policy lead loop-dependent capabilities, while the append-mostly
2365
+ log leads the volatile user-status clump. It does **not** claim that every system byte is
2256
2366
  immutable or that the complete packet is globally monotone in volatility:
2257
2367
  capabilities, operator notes, and policies can change. Trust is a separate
2258
2368
  admission rule. The system slot contains trusted control-plane material;
@@ -2279,48 +2389,58 @@ grinding and folding remain closed engine concerns.
2279
2389
  Token accounting distinguishes the artifact being measured, the unit, and the
2280
2390
  time of measurement.
2281
2391
 
2282
- | Quantity | Source and unit | When | Contract |
2283
- |:-----------------------------------------------------------|:------------------------------------------------------------------|:--------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------|
2284
- | Provider usage | Provider-reported prompt/completion/reasoning tokens | After generation | Durable cost and transport forensics; never the pre-call packet budget. |
2285
- | Packet render-weight | `rulerCount = ceil(chars/2)` over rendered slots | Every packet build | Drives the Budget readout and grinder. |
2286
- | Stored content-depth | The same ruler over entry/log content | When content is written | Weights catalog and log rows without per-model workspace state. |
2287
- | §tokenomics-physical-admission Physical recovery admission | Provider measurement of the complete `PacketWire` message request | Only when the grinder cannot satisfy policy | Exact counts and proven upper bounds may authorize recovery. Estimates, unavailable evidence, and unknown provider physics fail closed. Never model-facing. |
2392
+ | Quantity | Source and unit | When | Contract |
2393
+ |:--------------------------------------------------------------------|:------------------------------------------------------------------|:------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
2394
+ | Provider usage | Provider-reported input/output tokens and cache/reasoning details | After each physical request | Durable monetary and transport forensics under {§provider-usage}; never the pre-call packet budget. |
2395
+ | Packet render-weight | `rulerCount = ceil(chars/2)` over rendered slots | Every packet build | Drives the Budget readout and grinder. |
2396
+ | Stored content-depth | The same ruler over entry/log content | When content is written | Weights catalog and log rows without per-model workspace state. |
2397
+ | §tokenomics-context-envelope-admission Hard context-envelope admission | Provider measurement of the complete `PacketWire` message request | After the grinder leaves negative ruler pressure | Exact counts and proven upper bounds may admit the request within the effective total envelope. Estimates and unknown capacity fail closed. Never model-facing. |
2288
2398
 
2289
2399
  - §tokenomics-tokens-stored-at-write **Ruler tokens, stored at write.** `entry_channels.tokens` and `log_entries.tokens` are populated with the model-independent `rulerCount` when their content is written. The stored number is a stable content-depth measurement, not a provider-specific prediction.
2290
2400
  - §tokenomics-render-weight-budget **Render-weight budget.** The budget headline — `ceiling`, `tokenUsage`, `tokensFree` — is the ruler measurement of the *assembled packet* after section transforms and budget substitution. Core measures minimum-width probes, monotonically expands fields that do not fit, then right-aligns the final values into those same widths; final substitution is length-invariant and displayed usage equals the stored request weight. A `SUM` of stored content-depth would measure different artifacts and cannot substitute for packet render-weight.
2291
2401
  - §tokenomics-context-percent **Prompt-budget percent.** The headline carries usage as a percent of the enforced model-facing budget — `usage Y (P%)` — beside the absolutes. It reads the ceiling already in hand; no extra provider call.
2292
- - §tokenomics-window-partition **Provider capacity and virtual pressure are
2293
- separate.** The provider owns physical context and generation settings. Core
2294
- derives the natural prompt capacity from that envelope and its packing-safety
2402
+ - §tokenomics-window-partition **Hard capacity and virtual pressure are
2403
+ separate.** The provider owns the effective total context envelope and
2404
+ generation settings. The envelope is already the minimum of model capacity
2405
+ and any stricter operator context cap ({§model-fact-resolution}); that cap is
2406
+ final. Core derives the natural prompt gauge from the envelope and its packing-safety
2295
2407
  margin. `PLURNK_SERVICE_PROMPT_BUDGET` is an optional alias-scoped virtual
2296
2408
  ceiling:
2297
2409
  `promptBudget = min(configuredPromptBudget, naturalPromptCapacity)`. Unset
2298
2410
  uses the natural capacity. The virtual ceiling controls only the packet gauge
2299
- and grinder; it never changes provider context, reasoning, completion, or
2411
+ and grinder; it never changes the hard context envelope, reasoning, completion, or
2300
2412
  `maxTokens`.
2413
+ - §tokenomics-prompt-projection-share **Prompt projection is stable packet policy.**
2414
+ `PLURNK_SERVICE_PROMPT_PROJECTION` is a required alias-scoped percentage in
2415
+ `(0, 100)`. It allocates that share of the enforced `promptBudget` to the
2416
+ aggregate automatic prompt-body projection. It does not bound stored prompt
2417
+ size, provider capacity, an explicit READ/FIND result, or the complete packet.
2418
+ Basing the share on the stable ceiling rather than current free weight keeps
2419
+ one prompt's projection byte-stable as the worker log evolves.
2301
2420
  - §tokenomics-window-unpollable-deliberate **Unknown provider capacity stays
2302
2421
  unknown.** Without a configured virtual ceiling, an unknown provider window
2303
2422
  leaves the prompt uncapped and omits denominator-dependent gauge telemetry. A
2304
- configured virtual ceiling still bounds PLURNK's packet without pretending
2305
- to describe provider physics. An over-policy recovery candidate cannot be
2306
- physically authorized without a known provider window and output envelope.
2423
+ configured virtual ceiling still supplies PLURNK's curation gauge without
2424
+ pretending to describe hard capacity. A negative-gauge request cannot be
2425
+ admitted without a known effective context and generation envelope.
2307
2426
 
2308
2427
  §tokenomics-client-gauge **The client gauge pairs current occupancy with its
2309
2428
  effective ceiling.** A model switch changes both latest-turn values together;
2310
- the loop-total usage fields remain billing evidence, not gauge inputs.
2429
+ the loop's aggregate provider accounting remains monetary evidence, not a gauge
2430
+ input.
2311
2431
 
2312
- | Surface | `contextTokens` | `promptBudget` |
2313
- | -------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
2314
- | `loop/terminated.usage` | Latest provider attempt on the latest turn; `0` when none completed | Latest turn's enforced packet allowance; `null` when uncapped or unknown |
2315
- | `providers.list` alias row | not present | Active alias's current enforced packet allowance; `null` when not established |
2432
+ | Surface | `contextTokens` | `promptBudget` |
2433
+ | -------------------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
2434
+ | `loop/terminated.usage` | `inputTokens` from the latest settled physical request on the latest turn; `null` when absent or unknown | Latest turn's enforced packet allowance; `null` when uncapped or unknown |
2435
+ | `providers.list` alias row | not present | Active alias's current enforced packet allowance; `null` when not established |
2316
2436
 
2317
2437
  - **Derivation is eager and exhaustive.** Workspace creation and searchable-resource changes start one coalesced warm. The first model turn joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or vector coverage. A semantic query ranks every eligible candidate in scope, so lexical overlap never gates vector recall. With no embedder, readable-content FTS is the explicit keyword fallback. Progress notices make the wait visible; latency is never hidden by partial semantics. {§derivation-exhaustive}
2318
2438
  - §membership-binary-sniff **Binary truth beats the label; no entry dominates the corpus.** A tracked member whose HEAD bytes contain NUL enters {§membership-source-projection} as `application/octet-stream` **regardless of what extension-based detection claims**; byte-level evidence outranks a default label. Every eligible text is tiled losslessly to the embedder window and every tile is embedded before its derivation attaches; semantic ranking max-pools the best chunk per candidate.
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.
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.
2439
+ - §tokenomics-agnostic-ruler **One model-agnostic ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. The complete model-facing ledger therefore uses `rulerCount = ceil(chars/2)`: one content has one number regardless of which model reads it, with no per-model workspace state or recount pass. Nonnegative-gauge packets rely on that ruler. Only a negative-gauge packet invokes the shipping provider's request-shaped hard-envelope measurement.
2440
+ - §tokenomics-neutral-telemetry **Budget telemetry is state, with one pressure alarm.** The model-facing Budget ordinarily has exactly one line: token ceiling, current usage and percentage, and free tokens. When free tokens are negative, exactly one second line reads `Context Token Budget Panic: YOU MUST FOLD or KILL enough less-relevant log items to restore free tokens.` Per-entry weights remain on log rows where they describe the entries themselves. Packet-level composition, rankings, and visualizations are absent. OPEN/FOLD/KILL remain the ordinary curation capabilities; no deterministic recovery process is prescribed.
2321
2441
  - §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as a stable per-content identity. `tokens` is stored in ruler units beside that content and is never keyed or recomputed by model.
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.
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.
2442
+ - §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own logical response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` is an exact decimal string only when every request is expressible in USD and is `null` otherwise. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot FOLD, so they never alter the model-facing Budget ledger.
2443
+ - §tokenomics-negative-pressure **Negative ruler pressure is honest and nonterminal.** The readout describes the packet the model actually receives: usage and percent may exceed the virtual ceiling, and free tokens equal `ceiling - usage` without flooring. Crossing the ceiling records {§grinder-overflow-problem}, then the grinder ({§grinder}) folds only the newest boundary. If the rebuilt packet remains negative but exact or proven-bounded request evidence fits the effective hard envelope, generation proceeds under the ordinary operation contract. Overflow creates no strike or one-turn quota; only failed hard-envelope admission terminally rejects generation.
2324
2444
 
2325
2445
  ### §membership Workspace identity, membership, disk co-location
2326
2446
 
@@ -2361,7 +2481,7 @@ query is the absolute identity ({§scheme-address-network}); the sanitized
2361
2481
  readable projection is the fragmentless default, while faithful DOM, origin
2362
2482
  media type, and projection identity remain explicit auxiliary evidence. A
2363
2483
  normal
2364
- `READ(https://host/path?query)` therefore publishes only the sanitized body
2484
+ `## READ0 (https://host/path?query)` therefore publishes only the sanitized body
2365
2485
  under that exact URL—never raw HTML, response headers, or a channel-selection
2366
2486
  lesson. FIND and embeddings consume the same stored readable
2367
2487
  projection and never re-fetch each match. Because the search family is in
@@ -2369,7 +2489,7 @@ projection and never re-fetch each match. Because the search family is in
2369
2489
  ({§exec-hold-until-concluded}), so the next packet contains final
2370
2490
  materialization verdicts and folded ambient rows for every acquired page.
2371
2491
 
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.
2492
+ §search-gate Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin search→materialize→FIND and persistence/publication separation. Model web demos run the live composition end to end — real SearXNG, real pages; stubbed acquisition is confined to unit and integration seams and never appears in a demo. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page. Live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions. **The search gates** are rail-family accounting — in-memory per-loop state cleaned at the same seam as strikes, restart-drop accepted (a post-restart duplicate re-fetches; the TTL makes it cheap): an IDENTICAL duplicate (same runtime + query in one loop) **strikes and serves** — status 409 (the strike rail counts the turn failure) carrying the prior ranked digest re-read live from the original exec entry, no re-fetch, no provenance prose; the per-turn CAP (`PLURNK_SERVICE_SEARCH_MAX_PER_TURN`) is flood control — 429 with a legible steer, nothing served.
2373
2493
 
2374
2494
  **Git is the substrate and the repository is the boundary:**
2375
2495
 
@@ -2393,7 +2513,8 @@ materialization verdicts and folded ambient rows for every acquired page.
2393
2513
  and directs the operator back to the default. The isomorphic untracked scan
2394
2514
  remains differential-gated against native
2395
2515
  `ls-files --others --exclude-standard`.
2396
- - §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** stays open — proposal→accept adds it to the manifest. Reaching past membership is `EXEC[sh]`'s job, not the file scheme's.
2516
+ - §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** stays open — proposal→accept adds it to the manifest. Reaching past membership is `## EXEC0 [sh]`'s job, not the file scheme's.
2517
+ - §membership-create-parents **Parent-complete creation.** An accepted File creation—whether authored as EDIT or as a COPY/MOVE destination—recursively creates missing parent directories before writing and registering the new member.
2397
2518
 
2398
2519
  **The overlay — `pick | view | hide`, removed by `drop`.** A `workspace_constraints` table is the client's supersede over Git. Resolved membership is `(project repository files ∪ pick) − hide`, with `view` enforced at the edit gate.
2399
2520
  - §membership-auto-add **Auto-add** — the project repository's membership is its tracked `ls-files` plus untracked-but-not-ignored files (`git ls-files --others --exclude-standard`), with `git` origin. A model-created file is a member the moment it exists—no `git add`—while `.gitignore` still filters it.
@@ -2417,6 +2538,12 @@ identity, and terminal disposition without exposing raw bytes or a base64 lane.
2417
2538
 
2418
2539
  §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ body, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A resource attaches the immutable artifact only after it is complete; identical entry and log bodies therefore share one FTS row, one symbol graph, and one vector set without copying. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every resource completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
2419
2540
 
2541
+ The artifact also retains a positive `{§mimetype-parse-issues}` count when the
2542
+ exact parsed body reported one. It remains advisory alongside a normally
2543
+ completed semantic disposition; zero and unavailable evidence persist as
2544
+ absence. Catalog projection attaches it only to that parsed body channel, never
2545
+ to sibling channels whose content the artifact does not describe.
2546
+
2420
2547
  Every completed artifact records one terminal disposition: `vector`, `lexical`
2421
2548
  (only no embedder or an operator size ceiling), `excluded` (the configured
2422
2549
  search-exclusion table), `nonsemantic` (empty/binary/no embedding content), or
@@ -2439,7 +2566,7 @@ Lossless chunk admission requires either the embedder's own counter or an exact
2439
2566
 
2440
2567
  §membership-emi-divergence-signal **EMI divergence signal.** The detector that gates the work *is* the one that fires this — one mechanism, not a second full read. When the change-detect finds a member moved out-of-band, the delta detector ({§env-delta}) surfaces it as a system `EDIT` log row naming the file, `source="file"` — the model sees what changed without diffing the manifest against memory. The model's own edits are write-through (the entry equals disk after a File write), so the scan never mis-attributes them as external divergence.
2441
2568
 
2442
- §membership-edit-write-cas **The write-back is a compare-and-swap — never a clobber, never a clever merge.** EDIT is *naive against the editable text snapshot*: it diffs the model's change onto the entry's body channel — the exact Unicode the model READ — and the proposal carries the `synced_sig` that snapshot was taken at. Binary sources are refused before this path ({§membership-source-projection}). At accept, `applyResolution` re-stats disk and lands the proposed content only if that signature still matches. If disk moved out-of-band in the propose→accept window — a sibling worker, the user's editor, a build step — the write is **refused** with a `write_conflict` and **nothing is written**. The engine neither blind-writes over the ambient change (a *clobber*) nor silently re-diffs the model's edit against a state it never saw (getting *clever*) — both would bury a stale-view contract violation under a fallback. The conflict surfaces instead: a ≥400 apply downgrades to a reject ({§proposal}), so the model sees the EDIT **did not occur** (400; the `write_conflict` outcome is forensics-only), the next reconcile narrates the real disk content as a `source=file` divergence ({§membership-emi-divergence-signal}), and the model re-reads and re-proposes against the fresh snapshot.
2569
+ §membership-edit-write-cas **The write-back is a compare-and-swap — never a clobber, never a clever merge.** EDIT is *naive against the editable text snapshot*: it diffs the model's change onto the entry's body channel — the exact Unicode the model READ — and the proposal carries the `synced_sig` that snapshot was taken at. Binary sources are refused before this path ({§membership-source-projection}). At accept, `applyResolution` re-stats disk and lands the proposed content only if that signature still matches. If disk moved out-of-band in the propose→accept window — a sibling worker, the user's editor, a build step — the write is **refused** with the same neutral `edit-collision` as {§edit-collision}, and **nothing is written**. The engine neither blind-writes over the ambient change (a *clobber*) nor silently re-diffs the model's edit against a state it never saw (getting *clever*) — both would bury a stale-view contract violation under a fallback. The collision surfaces instead: a ≥400 apply downgrades to a reject ({§proposal}), so the model sees that EDIT **did not occur** (400; the `edit_collision` outcome is forensics-only), the next reconcile narrates the real disk content as a `source=file` divergence ({§membership-emi-divergence-signal}), and the model re-reads and re-proposes against the fresh snapshot.
2443
2570
 
2444
2571
  The version travels *with the proposal*, never re-read from the entry at accept: a sibling worker in the same workspace may reconcile while this proposal sits paused, advancing the entry's `synced_sig` to the drifted disk — comparing against the *current* entry sig would wave that clobber through, so the comparison is always against the sig the proposal was computed at. A proposal that assumed an **absent** path (a create) conflicts only if a file has since appeared; a member with **no recorded snapshot** (an un-materialized entry, null `synced_sig`) has no baseline to guard and writes through — the two are told apart by the proposal's `existed` flag, not by a null sig alone. On a clean landing the entry refreshes to the written content and `synced_sig` is **restamped** to it, so the next reconcile recognizes the model's own write (not an external divergence) and a second same-turn edit bases on the landed bytes, not a stale sig. This is the write-side twin of the read-side change-gate ({§membership-change-gated-sync}): one `synced_sig`, gating both the re-read and the write.
2445
2572
 
@@ -2449,65 +2576,51 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
2449
2576
 
2450
2577
  **Rationale.** Workspace is the right scope unit and the containing Git repository is its ordinary development boundary. Membership curation is tiered: Git bounds it by tracking, the client supersedes by overlay, and the model curates its render by READ/FOLD. Supporting several independent repositories as one world would require Plurnk-owned topology, synchronization, and model teaching that Git already solves cleanly by treating them as separate workspaces.
2451
2578
 
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.
2579
+ **Schema.** The version-1 baseline stores logical model calls beneath turns,
2580
+ emission admission as their specialization, and cardinal physical requests
2581
+ beneath each call. Its constraints distinguish pending calls, response
2582
+ evidence, and response-less errors while monetary classification remains
2583
+ explicit.
2455
2584
 
2456
2585
  ### §grinder Budget enforcement: the grinder
2457
2586
 
2458
- The grinder is the one pre-provider enforcement path for the model-facing prompt
2459
- ceiling. Its sequence is deterministic:
2587
+ The grinder is the one pre-provider curation path for the model-facing prompt
2588
+ gauge. Hard admission remains a separate predicate over the effective total
2589
+ context envelope:
2460
2590
 
2461
2591
  ```mermaid
2462
2592
  flowchart TD
2463
- assemble["Assemble and measure<br/>request packet"] --> policy{"Within policy ceiling?"}
2593
+ assemble["Assemble and measure<br/>request packet"] --> policy{"Nonnegative<br/>ruler gauge?"}
2464
2594
  policy -->|yes| unchanged["Provider generate<br/>packet unchanged"]
2465
- policy -->|no| fold["FOLD newest boundary<br/>tag overflow; mark budget strike"]
2595
+ policy -->|no| problem["Record nonterminal 413<br/>Token Budget Overflow"]
2596
+ problem --> fold["FOLD newest boundary<br/>and its OPEN effects<br/>tag overflow"]
2466
2597
  fold --> rebuild["Rebuild and remeasure"]
2467
- rebuild --> folded{"Within policy ceiling?"}
2468
- folded -->|yes| receipt["Record fold-to-fit Problem<br/>rebuild and remeasure"]
2469
- receipt --> finalPolicy{"Still within policy ceiling?"}
2470
- finalPolicy -->|yes| recovered["Provider generate<br/>with recovered packet"]
2471
- folded -->|no| candidate["Hard-recovery candidate"]
2472
- finalPolicy -->|no| candidate
2473
- candidate --> physical{"Candidate physically sendable?"}
2474
- physical -->|no| stop["413 hard stop<br/>no provider call"]
2475
- physical -->|yes| grant{"Recovery grant unused?"}
2476
- grant -->|no| stop
2477
- grant -->|yes| steer["Record recovery Problem<br/>preserve the ordinary operation contract<br/>rebuild"]
2478
- steer --> finalPhysical{"Final packet physically sendable?"}
2479
- finalPhysical -->|yes| recovery["One informed<br/>provider call"]
2480
- finalPhysical -->|no| stop
2598
+ rebuild --> folded{"Nonnegative<br/>ruler gauge?"}
2599
+ folded -->|yes| recovered["Provider generate<br/>with folded packet"]
2600
+ folded -->|no| admission{"Exact or bounded request<br/>fits hard envelope?"}
2601
+ admission -->|yes| pressured["Provider generate<br/>with negative Budget alarm"]
2602
+ admission -->|no / unknown / estimate| stop["413 hard stop<br/>no provider call"]
2481
2603
  ```
2482
2604
 
2483
2605
  §grinder-overflow-only **The grinder fires only on actual overflow.** In
2484
2606
  `Engine.runTurn`, after `PacketBuilder.buildRequestPacket` assembles the request
2485
2607
  and before `provider.generate`, it compares the packet's render-weight
2486
- ({§tokenomics}) with the policy ceiling. At or under the ceiling, the packet
2487
- ships untouched and the recovery grant clears. The grinder never trims
2608
+ ({§tokenomics}) with the virtual ceiling. At or under the ceiling, the packet
2609
+ ships untouched. The grinder never trims
2488
2610
  speculatively or "helpfully."
2489
2611
 
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.
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.
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.
2612
+ - §grinder-overflow-problem **Token Budget Overflow is a nonterminal 413 Problem.** Every over-ceiling assembly records exactly one `engine/context/token-budget-overflow` Problem before automatic recovery, with pre-recovery `usage`, `ceiling`, and `deficit` evidence. Its exact `detail` is `Token Budget Overflow: Token Usage exceeded Token Ceiling. Newest log items were automatically FOLDed to fit within token budget. Curate the log and/or perform more conservatively scoped or chunked retrieval operations to recover.` The Problem remains durable and model-visible even when folding restores room and the turn later concludes successfully; it does not strike or replace the turn's terminal disposition.
2613
+ - §grinder-layer1-rollback **One rule, every turn: roll back context introduced by the newest boundary.** On overflow the grinder folds, in one set operation, still-open rows born in the immediately prior turn or current pre-model turn plus exact older rows that a successful OPEN in the immediately prior turn transitioned from folded to open. It reads those landed effects from {§fold-open-meta-operations}; it never re-runs the selector, treats an already-open target as newly introduced, or chooses other older history by relevance. Turn 1 has no prior turn, so only its pre-model rows qualify. The same set operation additively applies the `overflow` tag to every row it folds; rows and bodies remain re-OPENable.
2614
+ - §grinder-errors-exempt **Errors, the prompt, AND the plan are exempt.** The grinder never folds an `op='error'` row: errors are the model's durable, curatable record of what went wrong. Nor does it fold the actionless **user prompt** row (`prompt:///<loop>/<N>`): the task frame is not ordinary model-authored memory. Nor a **PLAN row**: the checklist is the model's orientation surface when the grinder fires. All three stay OPEN until the model itself FOLDs or KILLs them.
2615
+ - §grinder-hard-413 **The terminal hard stop belongs only to effective-envelope admission.** If the rebuilt packet remains ruler-negative, Core measures the complete `PacketWire` request and reserves the configured generation envelope. Exact or proven-bounded evidence within `provider.contextWindow` admits an ordinary turn regardless of ruler debt. Unknown capacity, an estimate, or evidence exceeding the effective prompt capacity abandons the loop immediately at **413 Content Too Large** without calling `provider.generate`. The terminal request stores one `engine/context/context-envelope-admission-failed` Problem with ruler pressure and admission evidence, distinct from the preceding nonterminal overflow 413; it is failure forensics, not a model recovery turn.
2494
2616
 
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.
2617
+ - §tokenomics-fetch-fits-free **A retrieval larger than the available packet room arrives folded with a 413 explanation.** The result lands in the next build; if that build exceeds the ceiling, Core records {§grinder-overflow-problem} and folds the newest boundary, which contains the result. Its row and exact body remain durable and re-OPENable, and its `overflow` tag identifies every row selected by the automatic fold. Remaining ruler debt follows {§tokenomics-negative-pressure}.
2496
2618
 
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.
2619
+ - §loop-terminals **Engine-imposed terminals are HTTP-precise** — the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND signal `200`) · `499` model-abandoned (signal `499`, or a cancel) · `429` maxTurns exhausted · `413` effective context-envelope admission failed · `500` strike threshold or invalid-emission exhaustion (distinct Problem types; `508` when the crossing strike was a detected cycle) · `504` loop timeout / exec-timeout restamp · `202` the bounded wait — a loop blocked on a live obligation (the model's `## SEND0 [202] <T,P>`, {§wait-obligation-matrix}); a wait on nothing resolves to `200` unless a successful same-turn FOLD requires the curated next packet · `100`/`102` queued/running. Never a catch-all, never a new value without changing the owning schema.
2498
2620
 
2499
- §grinder-strike-coupling **Strike coupling.** A grinder fire bumps the engine's
2500
- per-turn rail verdict, so an overflow contributes one strike under
2501
- {§engine-rails}. If cycle detection also fires on that turn, the turn still
2502
- contributes only one strike and a threshold crossing is classified as 508.
2621
+ §grinder-pressure-surface **What the model sees.** A fold-to-fit packet carries the open {§grinder-overflow-problem} row, its terse `## Errors` pointer, and ordinary folded rows whose complete sorted `tags` include `overflow`. If ruler pressure remains negative but hard admission succeeds, the Budget section also reports the negative free-token value and its one panic line ({§tokenomics-neutral-telemetry}). The 413 diagnoses the overflow without striking, terminalizing the turn, or changing the ordinary operation contract.
2503
2622
 
2504
- §grinder-fold-strikes **Every grinder fold strikes, including turn 1.** There
2505
- is no soft exemption. Folded rows still cost their coordinate lines, so
2506
- repeated overflow can legitimately reach the strike threshold.
2507
-
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.
2509
-
2510
- The model controls its context; the engine enforces packet physics without
2623
+ The model controls its context; the engine enforces the hard envelope without
2511
2624
  choosing what older history matters. The same boundary applies on turn 1 and
2512
2625
  turn 101. The grinder folds reversibly, never deletes, and never performs
2513
2626
  speculative or non-overflow trimming.
@@ -2534,7 +2647,8 @@ flowchart LR
2534
2647
  pre-turn, a worker materializes every other actor's event on shared state after
2535
2648
  its last completed observation boundary into its own log. The set is
2536
2649
  exhaustive, unranked, and exactly once; the engine makes no relevance decision.
2537
- Each copied event retains its effect, cause, and typed attributes. Every
2650
+ Each copied event retains its effect, cause, typed attributes, and initial
2651
+ log classifications ({§log-item-tags}). Every
2538
2652
  producer appends to one workspace-scoped occurrence journal with a monotonic
2539
2653
  identity. A pull captures one closed `(worker cursor, high-water]` interval,
2540
2654
  materializes each identity idempotently, then advances the cursor only after the
@@ -2620,16 +2734,22 @@ the aggregate remains dispatch coordination state.
2620
2734
  | -------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
2621
2735
  | Full `revision` | `rev` abbreviated to `PLURNK_SERVICE_EDIT_RECEIPT_REVISION_CHARS` | SHA-256 identity of the complete landed channel body; display correlation only, never a lookup or compare-and-swap token. |
2622
2736
  | `unit`, `before`, `after` | `extent` | Whole-line batches use line counts. A batch containing any exact four-coordinate edit uses Unicode code-point counts. |
2737
+ | `parseIssues` | `parseIssues` | Positive parser-recovery count for the complete landed revision; clean, unsupported, and unavailable evidence is omitted. |
2623
2738
  | `effect.requested`, `source`, `result` | `range` | The admitted marker and its normalized mapping from the common source snapshot into the landed body. |
2624
2739
  | `effect.removed`, `inserted` | `change` | Removed and inserted counts in the receipt unit. |
2625
- | `effect.context` | Canonical row body | Numbered physical lines around the landed join, bounded by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
2740
+ | `effect.context` | Canonical row body | Numbered physical lines at each landed boundary, bounded symmetrically by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
2626
2741
  | `disposition`, `requested` | `disposition`, `requested` | A reviewer-replaced batch preserves the authored marker while stating that its attributed effect was superseded. |
2627
2742
  | `replacement` | `replacement`, `change`, canonical proposal-owner body | The one whole-resource effect actually applied by the reviewer replacement; never duplicated across authored rows. |
2628
2743
 
2629
2744
  §edit-result-receipt-truth **Receipts describe committed state.** Every row in
2630
- one resource-channel EDIT batch carries the same landed revision and extent.
2745
+ one resource-channel EDIT batch carries the same landed revision, extent, and
2746
+ optional positive `parseIssues` count for that complete revision.
2631
2747
  When the proposed batch lands unchanged, each row also carries its own requested
2632
- marker, source/result mapping, counts, and context.
2748
+ marker, source/result mapping, counts, and context. For configured count `C`,
2749
+ the context contains up to `C` surrounding lines and the first and last `C`
2750
+ landed lines at the result boundaries. Overlapping windows coalesce; coordinate
2751
+ jumps expose an omitted middle. A deletion instead shows up to `C` lines on
2752
+ each side of its join.
2633
2753
 
2634
2754
  §edit-result-reviewer-replacement **A resolver replacement is one effect, not a
2635
2755
  guess at authorship.** An arbitrary accepted body replaces the batch's proposed
@@ -2675,7 +2795,10 @@ landed.
2675
2795
  | `304`, rejection, or cancellation with no landed mutation | `effects` omitted. |
2676
2796
  | Cross-selection MOVE source failure after destination success | The failure retains every destination effect that landed. |
2677
2797
 
2678
- Core validates the complete ordered array before exposing it.
2798
+ Core validates the complete ordered array before exposing it. Parser-recovery
2799
+ inspection is advisory and occurs against complete resulting text after
2800
+ successful application. A handler or parser failure emits a Notice, omits
2801
+ `parseIssues`, and never changes the mutation outcome.
2679
2802
 
2680
2803
  ### §proposal-ownership Loop auto and client YOLO
2681
2804
 
@@ -2705,7 +2828,7 @@ when an emission is admitted, its response.** Core assembles and measures the
2705
2828
  request under {§packet-assembly}. An admitted response extends that same record
2706
2829
  before the turn closes; a failed provider call or exhausted invalid emission
2707
2830
  leaves the request-only record, while rejected exchanges remain in
2708
- `turn_attempts`.
2831
+ `model_calls` with their classification in `turn_attempts`.
2709
2832
 
2710
2833
  | Turn state | `turns.packet` |
2711
2834
  | ----------------------------- | ----------------------------------------------- |
@@ -2753,7 +2876,7 @@ by service policy.
2753
2876
  |--------------------------------|----------------|
2754
2877
  | `worker` / `loop` / `turn` | The process hierarchy in {§lifecycle-terms}; unqualified `run` names no internal entity. |
2755
2878
  | `packet` | The assembled address space, a kernel concept rather than merely a provider request. |
2756
- | `costUsd` | No standard cost field exists; the explicit currency avoids implied units. |
2879
+ | `costUsd` | No standard cost field exists; the explicit currency avoids implied units, and the value remains an exact decimal string. |
2757
2880
  | `PLURNK_SERVICE_SAFETY` | The ruler's packing margin is a service fact no provider owns. |
2758
2881
  | the `chars/2` ruler | Model-agnostic by design ({§tokenomics-agnostic-ruler}). |
2759
2882
 
@@ -2767,7 +2890,7 @@ Core never decodes the blobs or renders them into a model packet; readable
2767
2890
  reasoning text remains separate in `assistant.reasoning`. The provider-detail
2768
2891
  identity and derived classification retain their exact provider-normalized
2769
2892
  meaning from {§provider-encrypted-reasoning}; core never reinterprets either as
2770
- a client entity. The mirror row and provider attempt remain the lossless
2893
+ a client entity. The mirror row and logical model call remain the lossless
2771
2894
  evidence when a downstream standard cannot represent the complete list.
2772
2895
 
2773
2896
  §body-projection **One full body, one packet projection.** Every durable log row has one canonical full body resolved from its stored tx/rx envelope by `LogBody`. READ and FIND over `log:///`, persistent search derivation, and packet rendering all consume that same meaning. Only packet rendering may project it:
@@ -2775,13 +2898,18 @@ evidence when a downstream standard cannot represent the complete list.
2775
2898
  | row producer | ordinary OPEN projection |
2776
2899
  |---|---|
2777
2900
  | any `READ` or `FIND` | complete selected operation result |
2901
+ | any `PLAN` | complete authored working memory |
2902
+ | actionless lowercase `prompt` | budgeted head under {§prompt-projection} |
2903
+ | structured `EDIT` receipt or textual `COPY`/`MOVE` effects | complete receipt-owned join context |
2778
2904
  | every other nonempty body | head bounded independently by `PLURNK_SERVICE_PREVIEW_LINES` and `PLURNK_SERVICE_PREVIEW_CHARS` |
2779
2905
  | bodyless row | `"display":"none","body":""` |
2780
2906
 
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.
2907
+ READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. PLAN is likewise complete while OPEN: it is the model's explicit persistent reasoning inventory, not ordinary content that the model should have to retrieve from itself. Prompt rows follow their separate adaptive projection contract. Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again. Model-emission mirrors, SEND/WORK/FORK bodies, EXEC commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. When an OPEN projection differs from its canonical body, `chunk` follows the displayed `body` with the exact selected and complete extents defined by {§jsonplurnk}; complete and FOLDED bodies omit it. `## READ0 (log:///<coordinate>/<OP>)` applies its default or explicit text range to the canonical body; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. `## FIND0 (log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores the producer's projection without changing its bound. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
2782
2908
 
2783
2909
  §prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt:///<loop>/<N>` as an owner-keyed text/markdown entry, then published to its turn as one actionless lowercase `prompt` log row. No synthetic EDIT or READ operation is invented. The row is born OPEN and obeys {§body-projection}. The **Active User Prompts** section closes the user-slot status clump as a paths-only list (`* prompt:///<loop>/<N>`), so every frame remains directly READable even after its log row is folded or killed.
2784
2910
 
2911
+ §prompt-projection **Prompt storage is unbounded by model context; automatic materialization is not.** Core persists every accepted prompt completely before packet assembly. The selected provider's enforced `promptBudget` and the alias-resolved percentage from `PLURNK_SERVICE_PROMPT_PROJECTION` derive one aggregate ruler-weight allowance for OPEN prompt bodies. Complete prompt bodies render when their aggregate weight fits. Otherwise all OPEN prompt rows share the allowance: full bodies consume only their required share, unused shares are redistributed, and partial bodies render the largest leading complete-line region that fits their share or an exact character-bound prefix when the first physical line alone is larger. The sum of their rendered body weights never exceeds the allowance. Every partial body carries its exact `chunk` after `body`; the canonical `prompt:///` entry and `log:///` body remain complete and READ/FIND-addressable. Without an enforced packet ceiling the percentage is underivable, so prompt rows retain the ordinary bounded projection rather than inventing capacity. This policy never rejects, summarizes, or discards a prompt because it exceeds a context window.
2912
+
2785
2913
  §prompt-self-only The frame is self-only and owner-keyed:
2786
2914
  `entries.owner_id` carries worker identity while the address carries only the
2787
2915
  loop coordinate. Concurrent workers therefore hold distinct rows at the same
@@ -2806,7 +2934,7 @@ their row shape, and their ordering are ordinary FIND projections owned by
2806
2934
 
2807
2935
  The model's runtime alert surface has two distinct kinds of information:
2808
2936
 
2809
- - **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content and remain exclusively in `turn_attempts`.
2937
+ - **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery mirror under {§invalid-emission-attempts}.
2810
2938
  - **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `embed_progress`, and `grammar_unenforced` may appear once in the packet and broadcast live. They neither substitute for a failure result nor influence scheduling or recovery.
2811
2939
 
2812
2940
  The `log` is durable product truth. The `errors` section points at its failures
@@ -2843,7 +2971,7 @@ retain distinct contracts and lifetimes.
2843
2971
  | failure | row | status |
2844
2972
  |---|---|---|
2845
2973
  | action failure | the failed op's own row; the owning scheme supplies Problem Details | 4xx/5xx |
2846
- | budget overflow | `op='error'`, source `rail` or `engine`; `engine/grinder/budget-overflow` Problem Details | 413 |
2974
+ | context-envelope admission | `op='error'`, origin `plurnk`, source `engine`; `engine/context/context-envelope-admission-failed` Problem Details | 413 |
2847
2975
  | max commands exceeded | `op='error'`, origin `plurnk`, source `rail`; `engine/rail/max-commands-exceeded` Problem Details | 429 |
2848
2976
  | idle turn | `op='error'`, origin `plurnk`, source `rail`; `engine/rail/idle-turn` Problem Details | 409 |
2849
2977
 
@@ -2856,7 +2984,7 @@ retain distinct contracts and lifetimes.
2856
2984
 
2857
2985
  §notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `grammar_unenforced` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
2858
2986
 
2859
- §operation-result-no-error-scheme Private strike and cycle accounting stays engine-internal ({§rail-accounting-private}). Every failure within an accepted turn - a bounded parse error, failed action, or engine rail - is a LOG ITEM (`log:///<coord>`, `status_rx ≥ 400`) with Problem Details, foldable and re-OPENable. The `errors` section surfaces a derived pointer to each. Rejected provider attempts stay in the forensic attempt relation. There is **no bespoke `error://` scheme** and no ephemeral per-category failure buffer.
2987
+ §operation-result-no-error-scheme Private strike and cycle accounting stays engine-internal ({§rail-accounting-private}). Every failure within an accepted turn - a bounded parse error, failed action, or engine rail - is a LOG ITEM (`log:///<coord>`, `status_rx ≥ 400`) with Problem Details, foldable and re-OPENable. The `errors` section surfaces a derived pointer to each. Rejected emissions stay in the forensic model-call and admission relations. There is **no bespoke `error://` scheme** and no ephemeral per-category failure buffer.
2860
2988
 
2861
2989
  §notice-event-notify **Client surface.** Engine Notices broadcast live via the `notice/event` WS notification — `{ loopId, notice: { source, kind, level, message?, position?, …kind-specific } }` per the grammar's `Notice` schema — the moment they land, scoped to the loop's workspace. AG-UI projects the same observation as the custom `plurnk.notice` event. Failures do not broadcast on this surface: they are log rows, and the client reads them through `log.read` / the `log/entry` notification, the durable log.
2862
2990
 
@@ -2867,10 +2995,10 @@ retain distinct contracts and lifetimes.
2867
2995
  | Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its co-located `digest.sql`; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
2868
2996
  | `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
2869
2997
  | `digestDir` | Selects the output directory. `run` removes and recreates it so stale packet artifacts cannot survive; concurrent callers use distinct directories. |
2870
- | `workerId` | Narrows workers and every dependent loop, turn, attempt, log row, and rollup to that one worker. |
2998
+ | `workerId` | Narrows workers and every dependent loop, turn, logical model call, emission attempt, physical request, and log row to that one worker. |
2871
2999
  | `workspaceId` | Narrows workers and dependent evidence to one workspace; when both selectors are present they intersect. |
2872
3000
 
2873
- §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log row, including causal `source` and structured `attrs`, the exact Problem on every failed row, and each loop's exact terminal result. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and folded network-entry storage paths render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; packet files remain byte-identical records of what the model saw.
3001
+ §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log row, including causal `source` and structured `attrs`, every exact OPEN/FOLD target effect from {§fold-open-meta-operations}, the exact Problem on every failed row, each loop's exact terminal result, and every ordered physical provider request. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and folded network-entry storage paths render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; packet files remain byte-identical records of what the model saw.
2874
3002
 
2875
3003
  §digest-requiem **A requiem is an out-of-band forensic interview, not a worker
2876
3004
  turn.** It cannot execute operations or alter the audited history.
@@ -2880,9 +3008,9 @@ turn.** It cannot execute operations or alter the audited history.
2880
3008
  | Scope | One interview for each worker with model-bearing turns; journal-only workers are omitted. |
2881
3009
  | Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. |
2882
3010
  | Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
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. |
3011
+ | Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as both `workerId` and `primaryWorkerId`, making the synthetic interview its own root without asserting a live worker topology. |
2884
3012
  | Attempts | One call at `PLURNK_SERVICE_REQUIEM_MAX_TOKENS`; only an empty length-limited response receives one retry at `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS`. |
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. |
3013
+ | Artifacts | `requiem.md` carries testimony and exact nullable USD accounting. `requiem.json` is durably materialized before each call and preserves logical call state, messages, normalized responses, every physical request's state and accounting, and their shared aggregate projection. |
2886
3014
 
2887
3015
  §turn-lifecycle **Turn-lifecycle liveness.** Provider generation is the long, opaque window in a turn — one or more same-packet emission attempts may occur before the first committed op. A static client screen there is indistinguishable from a hang. The engine brackets the complete attempt window with two `notice/event` notices (`source: "engine:turn"`, `level: "info"`): `turn_awaiting_model` before the first call and `turn_generated` when an emission is accepted or the attempt budget is exhausted. Rejected content never rides the notice channel. Both are suppressed on an aborted loop and broadcast to the workspace like any notice ({§notice-event-notify}).
2888
3016
 
@@ -2890,28 +3018,28 @@ turn.** It cannot execute operations or alter the audited history.
2890
3018
 
2891
3019
  ### §tools user.tools — the capability sheet
2892
3020
 
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.
3021
+ §tools-capability-sheet The tools capability sheet renders under `## Registered Tools`, after the policy sections. One generated Markdown table is the closed set of valid executor selectors and states each runtime declaration's model-facing `(target)` role, body role, and exact canonical example. The compact legend leaves required inputs unmarked, marks optional inputs with `?`, pairs mutually exclusive alternatives with `↔`, marks refused buckets with `—`, and locates optional `<timeout,poll>` on the heading. The preface prefers purpose-built Plurnk operations over EXEC scripts. For a declaration with `target.directory: "cwd"`, the target cell distinguishes a local-directory working context from the plugin-authored non-directory target role. Optional non-EXEC operations render separately under `## Enabled Optional Operations` in a `plurnk` fence, so the catalogue remains truthful. `PacketBuilder.#collectTools` assembles both; a prose notice (e.g. the EXEC-disabled line) stays beside the table, and empty sections are omitted.
2894
3022
 
2895
3023
  §tools-loop-affinity **The capability sheet describes the current loop.** The
2896
3024
  sheet filters registered capabilities through the same
2897
3025
  `SchemeRegistry.resolveForLoop(flags)` predicate the dispatcher enforces. When
2898
- registered executors exist but EXEC is inactive, their examples are replaced by
3026
+ registered executors exist but EXEC is inactive, their table is replaced by
2899
3027
  an explicit disabled notice rather than silent absence. The dispatch 403 remains
2900
3028
  the backstop and names the non-retryable loop restriction.
2901
3029
 
2902
- **Contributors: the wired executor tags.** Each available executor tag *with an example* contributes ONE bare op — its canonical usage — into the `plurnk` fence (identical shape to the scheme directory, schemes}); its doc is materialized at `worker://plurnk/docs/<tag>.md` and discovered via the turn-0 `FIND(worker://plurnk/docs/**)` foist, not linked inline. A tag with no example contributes nothing; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named tag's line + doc. The boot `ExecutorRegistry` probes availability per tag, so the catalogue advertises runnable selectors instead of presuming a particular runtime exists.
3030
+ **Contributors: the wired executor tags.** Every available executor tag contributes exactly one row derived from its requiredexecutor-invocation} declaration. Its doc is materialized at `worker://plurnk/docs/<tag>.md` and discovered via the turn-0 `## FIND0 [+init,+docs] (worker://plurnk/docs/**)` foist, not linked inline. `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named tag's row and doc. The boot `ExecutorRegistry` probes availability per tag, so the table advertises runnable selectors instead of presuming a particular runtime exists.
2903
3031
 
2904
- ### §schemes user.schemes — the scheme directory
3032
+ ### §schemes user.schemes — the resource directory
2905
3033
 
2906
- §schemes-directory A `## Schemes` section renders in the system slot **after the definition (plurnk.md — grammar + imperatives) and the tools sheet** — a terse directory of the scheme families available this workspace, so the model knows what URI schemes exist before it acts. Each scheme that ships a `manifest.example` contributes ONE bare op its canonical usage (no scheme prefix; the example self-documents) into a `plurnk` fence ({§tools} shares the shape). The doc is NOT linked inline — it is materialized at `worker://plurnk/docs/<scheme>.md` and discovered via the turn-0 `FIND(worker://plurnk/docs/**)` foist, keeping the raw packet free of doc links. Meta-owned `log` and `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls, the examples fenced like the tools sheet ({§tools}). A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's line + doc.
3034
+ §schemes-directory A `## Resources` section renders in the system slot **after the policy sections and tools sheet** — a terse directory of the scheme families available this workspace, so the model knows what URI resources and operations exist before it acts. Each scheme that ships a `manifest.example` contributes one or more concise canonical ops (no scheme prefix; each example self-documents) into a `plurnk` fence. Scheme example sets are separated by one blank line. The doc is NOT linked inline — it is materialized at `worker://plurnk/docs/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+docs] (worker://plurnk/docs/**)` foist, keeping the raw packet free of doc links. Meta-owned `log` and `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls. A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's examples + doc.
2907
3035
 
2908
3036
  ### §inject system.inject — the operator injection
2909
3037
 
2910
- §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot **right after the teaching** (definition → toolsschemes → inject), ahead of the policy sections part of the cached prefix. Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard (a deliberate setting with a broken path is a misconfig, surfaced not hidden). `~/` expands to home. It's the operator-side complement to the plugin section hook — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
3038
+ §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot after policy and capability teaching (definition → policyproject policy tools resources inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard (a deliberate setting with a broken path is a misconfig, surfaced not hidden). `~/` expands to home. It's the operator-side complement to the plugin section hook — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
2911
3039
 
2912
3040
  ### §policy system.policy — the client's policy injection
2913
3041
 
2914
- §policy-sections Two sections ride the system slot **below the operator notes, at the slot's bottom**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `~/.plurnk/AGENTS.md`) and `## Project Policy` from `PLURNK_SERVICE_PROJECT` (default `<projectRoot>/AGENTS.md`, resolved relative to the workspace root). AGENTS.md is **policy** — the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. Reference and scratch docs are NOT policy; `PLURNK_SERVICE_MD_*` materializes them as READ-able entries ({§operator-config}).
3042
+ §policy-sections Two sections ride the system slot **after the definition and before loop-dependent capabilities**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `~/.plurnk/AGENTS.md`) and `## Project Policy` from `PLURNK_SERVICE_PROJECT` (default `<projectRoot>/AGENTS.md`, resolved relative to the workspace root). AGENTS.md is **policy** — the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. Reference and scratch docs are NOT policy; `PLURNK_SERVICE_MD_*` materializes them as READ-able entries ({§operator-config}).
2915
3043
 
2916
3044
  On first run, and only when `~/.plurnk` itself is absent, the service seeds
2917
3045
  `AGENTS.md` from `@plurnk/plurnk-meta/PLURNK_PERSONALITY.md` ({§teaching-corpus}).
@@ -2920,7 +3048,7 @@ surfaces with its cause and leaves no apparently initialized home.
2920
3048
  After that bootstrap the file is user-owned: edits and deletion persist, and a
2921
3049
  later boot never refreshes or recreates it.
2922
3050
 
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.
3051
+ §schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path operation example set and the latter is the deep pull doc. `SchemeRegistry.teach()` renders the directory, `SchemeRegistry.docs()` resolves corpus-or-manifest documentation, and `docEntries()` materializes the result when core publishes capabilities for a workspace.
2924
3052
 
2925
3053
  ### §packet-git-status The Git status section — compact repository state
2926
3054
 
@@ -2968,7 +3096,7 @@ stored a resource.
2968
3096
  §graph-relations **Graph matching is one-hop, kind-agnostic name matching.**
2969
3097
  Source definitions resolve over the complete relationship universe (the
2970
3098
  workspace for entry FIND; the worker's complete log for log FIND), while the
2971
- authored target and tags still constrain every resource returned. Outgoing
3099
+ authored target still constrains every resource returned. Outgoing
2972
3100
  references belong to a definition through the handler-reported fully qualified
2973
3101
  container identity.
2974
3102
 
@@ -3050,7 +3178,7 @@ coordinates, inverted regions, out-of-range coordinates, and other arities are
3050
3178
  416.
3051
3179
 
3052
3180
  Every successful scoped READ carries its complete resolved `region` in the
3053
- operation result and packet metadata. The body remains line-numbered from
3181
+ operation result and packet metadata. The body remains coordinate-prefixed from
3054
3182
  `startLine`; the region preserves columns that line numbering cannot express.
3055
3183
 
3056
3184
  Every same-resource mutation resolves its replacement offsets against one
@@ -3060,7 +3188,7 @@ SARIF region/replacement algebra for exact spans and same-snapshot ordering, not
3060
3188
  adoption of the SARIF interchange envelope.
3061
3189
 
3062
3190
  §slice-semantics-compose-pattern **Compose from evidence.** A match region already uses the four-coordinate
3063
- scope shape. A follow-up `READ(resource)<SL,SC,EL,EC>` retrieves that exact
3191
+ scope shape. A follow-up `## READ0 (resource) <SL,SC,EL,EC>` retrieves that exact
3064
3192
  region. JSONPath/XPath remain locators and matchers; they do not introduce a
3065
3193
  second structural scope or structural EDIT language.
3066
3194
 
@@ -3081,15 +3209,18 @@ projection, and binary handling. Text scope meaning does not vary by mimetype.
3081
3209
 
3082
3210
  ### §render-rule Render rule
3083
3211
 
3084
- §render-rule-line-navigable-prefix Every textual content body with a source `startLine` renders with an `N:`
3085
- prefix on each physical line, independent of mimetype. JSON, XML, and HTML are
3086
- therefore just as line-addressable as markdown and source code. The prefix is a
3087
- packet presentation aid, never part of canonical content; matchers and
3088
- mutations consume canonical bytes before rendering. A producer may set
3089
- `startLine: null` only when its content is already source-numbered, such as an
3090
- effect receipt.
3212
+ §render-rule-line-navigable-prefix Every textual content body with a source
3213
+ `startLine` renders with a coordinate prefix on each physical line, independent
3214
+ of mimetype. A successful exact READ whose active scheme declares
3215
+ `textEditScopes: true` and model write authority supplies `@hash N:` with one
3216
+ or more ASCII spaces before `N` under
3217
+ {§line-anchors}; every other body renders `N:`. JSON, XML, and HTML are therefore just as
3218
+ line-addressable as markdown and source code. The prefix is a packet
3219
+ presentation aid, never part of canonical content; matchers and mutations
3220
+ consume canonical bytes before rendering. A producer may set `startLine: null`
3221
+ only when its content is already source-numbered, such as an effect receipt.
3091
3222
 
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.
3223
+ §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, model-emission, prompt, and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; EXEC and the composed PLAN/SEND/WORK/FORK family use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and the coordinate projection in {§render-rule-line-navigable-prefix}. READ/FIND over `log:///` and search consume the complete canonical body instead. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
3093
3224
 
3094
3225
  An `EDIT` log row renders its bounded effect receipt (`rx.receipt`) as row
3095
3226
  metadata and join context, not its input statement. Proposal-gated file EDITs
@@ -3100,7 +3231,8 @@ any scoped textual receipt contexts under their `log:///` address, never under
3100
3231
  one operand's resource address. All generated bodies remain under
3101
3232
  {§body-projection}. {§edit-result-render}
3102
3233
 
3103
- The `N:` prefix is presentation/reference per plurnk.md ("not part of the source"); stripped before any matcher operation on the log entry.
3234
+ Numeric and anchored coordinate prefixes are presentation/reference per
3235
+ plurnk.md ("not part of the source"); matchers operate on canonical content.
3104
3236
 
3105
3237
  ### §markdown-primitive Mimetype primitive: text/markdown
3106
3238
 
@@ -3122,7 +3254,7 @@ Carried from the contract walk; durable.
3122
3254
  - §copy-l-source-range **COPY/MOVE source scope** selects only the addressed source channel and
3123
3255
  first resolves and, when required, prepares the same canonical
3124
3256
  owner-addressed representation as exact READ/FIND. It transfers canonical
3125
- text without the packet's `N:` prefix. A MOVE removes
3257
+ text without the packet's coordinate prefix. A MOVE removes
3126
3258
  that same selected region; an unscoped MOVE removes only the selected
3127
3259
  channel, deleting the entry only when no channels remain. A binary marker
3128
3260
  is not transferable; a readable binary projection is already a textual
@@ -3136,10 +3268,11 @@ Carried from the contract walk; durable.
3136
3268
  Any scoped textual transfer materializes create/update receipts; whole-channel
3137
3269
  changes do not. Operand selections remain independently visible per
3138
3270
  {§copy-move-observation}.
3139
- - **READ rx** prefixes every textual line with `N:` per {§render-rule}.
3140
- - **FIND body matcher** applies to entry content (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). Scope + tags select candidates in SQL; the path-glob is the (target).
3271
+ - **READ rx** prefixes every textual line under {§render-rule}; eligible
3272
+ editable resources carry `@hash N:`, and all others carry `N:`.
3273
+ - **FIND body matcher** applies to entry content (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). The target scope selects candidates; the path-glob is the (target). FIND's signal classifies its own log item ({§log-item-tags}).
3141
3274
  - **OPEN/FOLD** operate on the **log** (`log:///`), not entries ({§open-fold}) — FOLD collapses a log row to its path, OPEN restores its body. Aimed at an entry scheme they return 501.
3142
- - **SEND[410]** deletes as a side-effect (not the model idiom; {§move}): with `#fragment`, that channel only; without, the whole entry. **SEND[499]** resolves the durable open-subscription row and invokes that subscription's exact callable owner through the process-local live registry ({§subscriptions}).
3275
+ - **SEND signal `410`** deletes as a side-effect (not the model idiom; {§move}): with `#fragment`, that channel only; without, the whole entry. **SEND signal `499`** resolves the durable open-subscription row and invokes that subscription's exact callable owner through the process-local live registry ({§subscriptions}).
3143
3276
  - **File scheme** detects with `Mimetypes.detect({ path })` and classifies with the same configured service ({§mimetype-classification-consumption}). Handler-declared binary sources materialize through {§membership-source-projection}; projected bodies are READ-able, while source-aware EDIT remains 415.
3144
3277
 
3145
3278
  ### §send-status-policy Directed-SEND status code policy