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