@plurnk/plurnk-service 0.59.0 → 0.60.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.example +12 -1
- package/SPEC.md +38 -32
- package/dist/core/Engine.d.ts +2 -0
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +234 -150
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +48 -10
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +8 -3
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +5 -1
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +52 -18
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/run-cap.js +2 -2
- package/dist/core/run-cap.js.map +1 -1
- package/dist/core/run-ops.sql +21 -0
- package/dist/schemes/Exec.js +1 -1
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/Run.d.ts.map +1 -1
- package/dist/schemes/Run.js +26 -26
- package/dist/schemes/Run.js.map +1 -1
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +5 -1
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +6 -0
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +24 -2
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/drain.sql +14 -0
- package/dist/server/methods/session_attach.d.ts.map +1 -1
- package/dist/server/methods/session_attach.js +4 -0
- package/dist/server/methods/session_attach.js.map +1 -1
- package/dist/server/methods/session_create.d.ts.map +1 -1
- package/dist/server/methods/session_create.js +4 -0
- package/dist/server/methods/session_create.js.map +1 -1
- package/migrations/0000-00-00.01_schema.sql +5 -1
- package/package.json +12 -12
- package/requirements.md +6 -9
package/.env.example
CHANGED
|
@@ -51,8 +51,12 @@ PLURNK_MODEL=plurnk
|
|
|
51
51
|
|
|
52
52
|
# PLURNK_API_KEY="..."
|
|
53
53
|
# PLURNK_BASE_URL overrides the default endpoint — self-host or point at a mirror that
|
|
54
|
-
# speaks the llama-server API (same grammar transport).
|
|
54
|
+
# speaks the llama-server API (same grammar transport). The `plurnk` provider defaults to
|
|
55
|
+
# https://plurnk.ai/v1 (providers 0.21.0). The trailing /v1 is REQUIRED — without it the
|
|
56
|
+
# host serves the website, not the OpenAI-compatible API.
|
|
55
57
|
# PLURNK_BASE_URL="..."
|
|
58
|
+
# Reach plurnk over Tor instead of the clearnet default (opt-in — uncomment):
|
|
59
|
+
# PLURNK_BASE_URL=http://plurnksnr2kihuukt6v22ko72r34dxeatbsfhgow3hvnlw6btanxphad.onion/v1
|
|
56
60
|
|
|
57
61
|
# --- Loop control ---
|
|
58
62
|
# Operator turn ceiling. -1 (default) = no cap (loops end via SEND, budget,
|
|
@@ -201,6 +205,13 @@ PLURNK_SEMANTIC_CHUNK_TOKENS=
|
|
|
201
205
|
# Overlap fraction [0,1): trailing context re-covered at each chunk boundary so a
|
|
202
206
|
# concept split across a cut still matches in both. ~0.15 is a standard RAG default.
|
|
203
207
|
PLURNK_SEMANTIC_CHUNK_OVERLAP=0.15
|
|
208
|
+
# embedBatch worker-pool size (read by @plurnk/plurnk-mimetypes-embeddings). Each worker
|
|
209
|
+
# holds its own model copy — a memory↔throughput dial (~6× at 8). Default min(cores, 8).
|
|
210
|
+
PLURNK_EMBED_WORKERS=8
|
|
211
|
+
# =1 forces the FTS-only path even with the embeddings package installed — the ~query
|
|
212
|
+
# degrades to keyword ranking and no vectors are derived (no MiniLM pool spun up). For
|
|
213
|
+
# hosts/runs that don't want vector search; the fast test lane sets it in .env.test.
|
|
214
|
+
PLURNK_EMBED_DISABLE=0
|
|
204
215
|
|
|
205
216
|
# --- Diagnostics ---
|
|
206
217
|
PLURNK_DEBUG=0
|
package/SPEC.md
CHANGED
|
@@ -176,11 +176,11 @@ Server posture: this package is the runtime. User-facing CLI lives in `plurnk` a
|
|
|
176
176
|
|
|
177
177
|
The run:// scheme makes §machine-processes addressable: a `run://` target is a sister run in the session — `run://self` the current run, `run://<name>` a session-scoped sibling (`runs.name`). `self` is the reserved current-run sentinel; empty authority (`run:///`) is invalid (400). Same-session only; a run never addresses another session's runs (§actor-boundary). The path discriminates the two faces: **path-absent is control** on the run-as-actor — the NAME is the authority (`run://<name>`, two slashes, no path) — while **path-present is run-scope storage**: `run://<owner>/<path>` (`run://self/<path>` for self) addresses the owner's private scratch (Scratch + Perspective, below). The control ops are three, fire-and-forget — the child runs independently, lineage in `runs.parent_run_id`:
|
|
178
178
|
|
|
179
|
-
- **Spawn** — `
|
|
179
|
+
- **Spawn** — `COPY(run://<name>):prompt` creates a new sister (empty log) and starts it with `prompt` on its first loop. COPY is the run-creation verb (grammar 0.74.41 OP×resource matrix): EDIT is file/entry only, so EDIT on the bare run entity is a **400** steering to COPY — the entity is not an entry. A name is **frozen per run** but **reclaimable across time** (§machine-processes-run-origin): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `run_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `run '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error. {§run-scheme-spawn}
|
|
180
180
|
- **irc** — `SEND(run://<name>):msg` delivers `msg` to an existing sister, the **voice door** (§actor-boundary-two-doors): an active sister folds it into its next turn, an idle one wakes (§actor-boundary-passive-wake); a name with no run in the session is 404. {§run-scheme-irc}
|
|
181
|
-
- **Fork** — `COPY(run
|
|
181
|
+
- **Fork** — `COPY(run://self):prompt` branches the current run: its log is deep-copied into a new sister (§machine-processes-fork-copies-the-log), which continues with `prompt`; the world is shared, never copied (§machine-processes-fork-shares-the-world). A fork ALSO inherits the run-scope **scratch** — its private workspace deep-copied with the owner remapped (source → branch) — so the branch opens with the parent's notes and diverges on its own edits: *fork = everything-in-common-but-name*. The `run://` authority disambiguates COPY's two run modes: `self` forks, a `<name>` spawns. {§run-scheme-fork} {§run-scheme-fork-scratch}
|
|
182
182
|
|
|
183
|
-
All three ride one engine seam — the daemon's inject (active→fold, idle→enqueue+drain) — so the handler creates/branches
|
|
183
|
+
All three ride one engine seam — the daemon's inject (active→fold, idle→enqueue+drain) — so the handler creates/branches the run and hands off; the daemon owns provider + system prompt. COPY's body here is the spawn/fork seed prompt, not a destination path: the engine routes a run:// COPY target away from the entry-copy path before parsing the body.
|
|
184
184
|
|
|
185
185
|
Beyond the three creation ops:
|
|
186
186
|
|
|
@@ -189,7 +189,7 @@ Beyond the three creation ops:
|
|
|
189
189
|
- **Perspective** — a run's own scratch is catalogued in **its** manifest alone — `Manifest(run) = session-scope ∪ this-run's-run-scope`, foisted as `FIND(run://self/**)` at turn 0 — so a sibling reaches it only by explicit `FIND(run://<name>/**)` and never sees it in its own perspective; isolation is structural (`scope='run'` is excluded from every session query, the owner opted back in only on its own read paths). {§run-scheme-find-perspective}
|
|
190
190
|
- **Terminate** — `KILL(run://<name>)` aborts a run by address (self is `run://self`): its active loop closes 499 and its subscriptions tear down; a name with no run is 404. The override to the fire-and-forget default — not a parent-power, whoever holds the address may end it; a run left alone simply ends at its own `SEND[200]`. {§run-scheme-terminate}
|
|
191
191
|
- **Cap** — `PLURNK_SESSION_RUNS_MAX_ACTIVE` ceilings the *concurrent* active runs per session (a run 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 sessions that live for months. {§run-scheme-cap}
|
|
192
|
-
- **Collect** — a run's loop reaching a terminal status surfaces to its sisters as an ambient delta (§env-delta): a `SEND` from `run://<name>` carrying the loop's deliverable — the `SEND[200]` body, or for an abandonment the reason. A **2xx deliverable is born OPEN** (its body materialized into the parent's packet, not hidden behind a fold): a child's success must reach the parent open and awakening, never a bodyless row. An abandonment (non-2xx) surfaces folded. Every death-path is stamped uniformly, so no termination is silent; collection is the shared world moving, never a verb. {§run-scheme-collect}
|
|
192
|
+
- **Collect** — a run's loop reaching a terminal status surfaces to its sisters as an ambient delta (§env-delta): a `SEND` from `run://<name>` carrying the loop's deliverable — the `SEND[200]` body, or for an abandonment the reason. A **2xx deliverable is born OPEN** (its body materialized into the parent's packet, not hidden behind a fold): a child's success must reach the parent open and awakening, never a bodyless row. An abandonment (non-2xx) surfaces folded. Every death-path is stamped uniformly, so no termination is silent; collection is the shared world moving, never a verb. **Child orientation.** Beyond the conclusion delta, every turn the system packet surfaces the live things THIS run *currently holds* — open streams (`## Plurnk Service Child Streams`) and unconcluded child runs (`## Plurnk Service Child Runs`) — as terse `* <status> <path>` pointers (the same shape as the errors section), just above it. A worker is otherwise marked only at spawn and at conclusion; in between it goes silent, so a model loses track of what it holds and premature-terminates. This is ORIENTING STATE, never advice: the model SEES its live subtree (`* 102 run://worker-x`, `* active sh:///1/2/3`) and reasons for itself — READ/OPEN/KILL via the path — the error stays terse. Empty → omitted, like errors. {§child-orientation} The **pull** side mirrors the push: a path-absent `READ(run://<name>)` collects the same deliverable on demand — the latest loop's terminal message (the result, or the abandonment reason) for a concluded run; a run **still running** has not delivered, so the READ returns **425** steering the model to `SEND[202]` and await the push. A missing name is 404. So the model never needs to guess a scratch path to "check on" a worker — reading the run itself yields its outcome or a wait. {§run-scheme-collect}
|
|
193
193
|
|
|
194
194
|
### §run-lifecycle Run lifecycle: the drain, the reap, the passive wake
|
|
195
195
|
|
|
@@ -200,7 +200,7 @@ A run is a **log plus a cancellation scope** — one `AbortController` per run,
|
|
|
200
200
|
- **A stream's kill binds to the scope it captured at spawn.** A stream captures the run's cancellation scope as it registers and wires its kill to it, re-checking `aborted` AFTER wiring — no check-then-listen gap can drop an abort that lands mid-registration. Because the scope is replaced only once aborted, a captured-then-replaced scope is necessarily already aborted, so replacement never strands a live stream. {§run-lifecycle-exec-epoch-bound}
|
|
201
201
|
- **A cancelled run is not resurrected by its own torn-down work.** A stream conclusion delivered to a cancelled, idle run 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 `loop.run` resumes the run. {§run-lifecycle-no-resurrection}
|
|
202
202
|
- **A stream conclusion always reaches its run.** When a backgrounded stream concludes, the daemon routes it through the same inject seam as any loop source (§actor-boundary-passive-wake): an active run folds the conclusion into its next turn; a run parked at a **slept loop** (`SEND[202]`) **awakens that loop in place** — the slept loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. The result is never lost: a parked loop sleeps rather than ending, and the stream's status-transition is the OPEN event (§actor-boundary-passive-wake) that wakes it; on resume it reads the concluded stream's own state, not a synthetic prompt. {§run-lifecycle-wake-liveness}
|
|
203
|
-
- **A child run concluding wakes a parent parked on it — the topology join.** `run://` spawn/fork records `parent_run_id` (§lifecycle-terms). When a run's drain exits having **concluded** — no parked `202` loop, no open stream — the daemon resumes its parent **in place** if the parent is parked (`#onDrainExit` → the shared `#wakeParkedRun`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and `SEND[202]`s is woken the moment its child finishes; on resume it reads the child's deliverable from the §run-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 parked 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 runs are the same kind of "live thing a run holds," driving premature-terminate (§send-premature-terminate), the wake edge, and the collect delta identically. {§run-lifecycle-child-wake}
|
|
203
|
+
- **A child run concluding wakes a parent parked on it — the topology join.** `run://` spawn/fork records `parent_run_id` (§lifecycle-terms). When a run's drain exits having **concluded** — no parked `202` loop, no open stream — the daemon resumes its parent **in place** if the parent is parked (`#onDrainExit` → the shared `#wakeParkedRun`, the same 202→100 resume a stream conclusion uses). So a parent that spawns work and `SEND[202]`s is woken the moment its child finishes; on resume it reads the child's deliverable from the §run-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 parked 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 runs are the same kind of "live thing a run holds," driving premature-terminate (§send-premature-terminate), the wake edge, and the collect delta identically. A worker-run conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its `202` commits), `#wakeParkedRun` finds it not-yet-slept and records an **owed wake**, which the drain honors at the parent's park — so a hibernation awaiting worker runs **always returns**, never dead-parks on a conclude-before-park race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a park open.) {§run-lifecycle-child-wake}
|
|
204
204
|
- **A 202 whose subtree is idle emits `loop/quiesced` — a soft signal, not a terminal.** When a loop parks at `SEND[202]` and its subtree is idle (no open stream, no non-terminal child), the daemon broadcasts `loop/quiesced` (§notifications) — the client's honest *"nothing is running under this run right now."* The loop **stays at 202 and is reawakable**: a later `irc`/`loop.run` resumes it (and it re-quiesces, re-firing). It is **never a terminal code** — in a topology where any sibling can `irc` any run, true finality below the session doesn't exist, so quiescence (not finality) is the honest "done." A subtree with any live thing emits nothing — that thing's conclusion is the wake edge, not a quiesce. This is also the dead-park resolution: a wake-edge-less 202 no longer hangs silently; it announces idleness while staying resumable. {§run-lifecycle-quiesced}
|
|
205
205
|
- **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. {§run-lifecycle-no-lost-loop}
|
|
206
206
|
|
|
@@ -599,7 +599,7 @@ The engine's failure terminals — **500** (strike threshold) and **508** (cycle
|
|
|
599
599
|
**Two engine error states verify the claim.** Neither is a status code the model learns; both are engine machinery (§engine-rails), pushed to the model as a steering hint on the next packet and **never** as the strike itself (the model sees errors that happened, never the engine's accounting — the gamification policy, §engine-rails). Each strikes (`turnErrors`) and lets the loop continue so the model can correct; a model that ignores the hint and keeps offending spins out to the engine's 500, seeing only the repeated hint, never the count. (Both live at `Engine.runLoop`'s turn close.)
|
|
600
600
|
|
|
601
601
|
- **Idle turn** {§send-idle-turn} — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If the turn's work is complete, terminate with 200. If awaiting a stream or run trigger, terminate with 202 to hibernate."*
|
|
602
|
-
- **Premature terminate** {§send-premature-terminate} — a `SEND[200]` while the run holds a **live thing**: an open stream/spawn (§subscriptions, §run-lifecycle-total-reap) **or a non-terminal child run** (§run-lifecycle — children and streams are the same kind of live thing a run holds). The model declared done with work still running. The engine **
|
|
602
|
+
- **Premature terminate** {§send-premature-terminate} — a `SEND[200]` while the run holds a **live thing**: an open stream/spawn (§subscriptions, §run-lifecycle-total-reap) **or a non-terminal child run** (§run-lifecycle — children and streams are the same kind of live thing a run holds). The model declared done with work still running. The engine **refuses the SEND with 409** at dispatch: the SEND row records the model's `[200]` attempt and body **faithfully** — never rewritten, never erased — stamped `status_rx=409` (Conflict), and auto-surfaces in the errors section like any `status≥400` op (a `log_entries.status_rx` may be 409; a *loop* status may not, so the loop simply never goes terminal — it stays a continue). Its outcome carries the actionable steer, verbatim: *"Attempted [200] termination despite active streams or worker runs. You may either hibernate [202] to wait or KILL them before terminating."* The attempt **strikes** (couples to the grinder, §grinder-strike-coupling): a model that won't stop premature-200ing escalates out via the rails (cycle/strike → 500/508), never a false 200.
|
|
603
603
|
|
|
604
604
|
**Dead-park caveat — read before changing 202.** A 202 is a real hibernation only when a **wake edge** exists. Two edges exist: a **stream conclusion** (§run-lifecycle-wake-liveness) and an EXEC **poll cadence** `<T,P>` (§exec-poll — a per-run timer resumes the slept loop every P). grammar 0.74.20 now **advertises** `SEND[202]` on the hot path, so the old "preventive" guard (un-advertising it) no longer holds. The remaining gap is the **wake-edge-*less* 202** — a model that parks with no open stream and no poll: it has nothing to resume it and *can* hang. The daemon-side check that detects and resolves a wake-edge-less 202 is the known backstop, still **deferred**; until it lands, do not assume a wake-edge guarantee for a 202 emitted with nothing running.
|
|
605
605
|
|
|
@@ -1104,8 +1104,8 @@ Each entry: question, answer, rationale, migration path.
|
|
|
1104
1104
|
|
|
1105
1105
|
- **Provider tokens, stored at write.** `provider.countTokens` is the source of truth; `entry_channels.tokens` (via `_entry-crud`) and `log_entries.tokens` (via `Engine.#writeLog`) are populated at write as a write-time snapshot. A `ceil(len/DIVISOR)` fallback (the divisor tripwire) applies only when no provider tokenizer is wired. {§tokenomics-tokens-stored-at-write}
|
|
1106
1106
|
- **Render-weight budget.** The budget headline — `ceiling`, `tokenUsage`, `tokensFree` — is measured from the *assembled packet* (placeholders substituted after measuring), so it reflects what the model actually receives. A `SUM` of stored content-depth would mis-price the rendered packet; render-weight is the accurate measure. {§tokenomics-render-weight-budget}
|
|
1107
|
-
- **Per-turn weight.** A markdown table groups render-weight by turn — the `loop/turn` coordinate prefix — oldest first
|
|
1108
|
-
- **Heaviest entries.** A second table lists the
|
|
1107
|
+
- **Per-turn weight.** A markdown table groups render-weight by turn — the `loop/turn` coordinate prefix — listed chronologically (oldest first). The turn is the grinder's rollback unit, and the rail folds the **newest** turn first (§grinder); the model sees which turns are fat and can FOLD ahead of the rail. {§tokenomics-turn-totals}
|
|
1108
|
+
- **Heaviest entries.** A second table lists the five heaviest log entries by render-weight, each by its `log:///<coord>/<op>` handle — the FOLD targets behind the turn weight. The handle carries the turn, so the two tables interlock. {§tokenomics-largest-entries}
|
|
1109
1109
|
- **Context-window percent.** The headline carries usage as a percent of the ceiling — `usage Y (P%)` — a fullness gauge beside the absolutes. Reads the ceiling already in hand; no extra provider call. {§tokenomics-context-percent}
|
|
1110
1110
|
- **Depth re-counted at render.** The manifest re-tokenizes each entry's `tokens` through the live provider at build — never the write-time snapshot — so a model change between loops can't stale the catalog. Every token figure in the packet is render-fresh, manifest and budget alike; nothing trusts a cross-loop cached total.
|
|
1111
1111
|
- **The delivered packet is never over budget.** The readout shows the state of the packet the model actually has, and the grinder (§grinder) folds any over-ceiling packet back under *before* it is sent — so a delivered budget headline is always usage ≤ ceiling, percent ≤ 100, free ≥ 0. The percent is of the **post-fold** packet; the pre-fold overshoot is engine trivia the model never sees. A packet that can't be folded under even fully collapsed is the corner case: the loop **hard-413s** rather than deliver an over-budget packet. Its STORED failure record renders the overshoot honestly — `free` floors at 0 (never negative), the percent passes 100 — never clamped to hide the degenerate state, but never the model's reasoning surface either. {§tokenomics-over-budget-floor}
|
|
@@ -1164,14 +1164,15 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
|
|
|
1164
1164
|
|
|
1165
1165
|
**Question.** §tokenomics surfaces the budget honestly and the model curates against `tokensFree` — almost always enough. Two states defeat self-regulation, neither the model's doing: a jumbo prompt (the turn-0 environment), and an unexpectedly large read. (A jumbo repo is no longer its own case — with no index nothing auto-renders the repo; it surfaces only as a large catalog `FIND`, which the model pages like any big result.) What enforces the ceiling when the signal isn't enough?
|
|
1166
1166
|
|
|
1167
|
-
**Decision — a pre-LLM grinder, fired only on actual overflow.** In `Engine.runTurn`, after the packet is assembled (`#buildRequestPacket`) and before `provider.generate`, the assembled render-weight (§tokenomics) is measured against the ceiling. At or under → the packet ships untouched; the grinder never trims speculatively or "helpfully." {§grinder-overflow-only} On overflow it
|
|
1167
|
+
**Decision — a pre-LLM grinder, fired only on actual overflow.** In `Engine.runTurn`, after the packet is assembled (`#buildRequestPacket`) and before `provider.generate`, the assembled render-weight (§tokenomics) is measured against the ceiling. At or under → the packet ships untouched; the grinder never trims speculatively or "helpfully." {§grinder-overflow-only} On overflow it folds the newest turn, then hard-stops if that isn't enough:
|
|
1168
1168
|
|
|
1169
|
-
- **
|
|
1170
|
-
- **
|
|
1169
|
+
- **Newest-turn rollback.** The grinder folds the newest turn in the packet, and ONLY that one: the immediately-prior turn's emissions (turn N>1, the latest output that pushed it over), or — when there is no prior turn — **turn 1's own foists** (the catalog/prompt). It never reaches older history; the model alone curates stale context via FOLD/KILL, and the engine never janitors. Folded, not deleted: rows and bodies persist and are re-OPENable, so log *history* is preserved while the render collapses to coordinates. {§grinder-layer1-rollback}
|
|
1170
|
+
- **Errors are exempt.** The grinder never folds an `op='error'` row — the budget-overflow it just minted, a parse failure, an action failure. Errors are the model's durable, curatable record of what went wrong; folding them away the moment they matter would blind the model to a recurring failure. They stay OPEN until the model itself FOLDs or KILLs them. {§grinder-errors-exempt}
|
|
1171
|
+
- **Hard stop.** If the packet still overflows after the newest-turn rollback, the loop abandons at **413 Content Too Large** (`engine_loop_set_status`) — the content genuinely won't fit, and the anchor's name is finally its status. Its sibling engine-imposed terminals are HTTP-precise too: `maxTurns` → 429, a strike-out → 500 (508 when cycle-driven) — no longer the old catch-all 499. No further passes. {§grinder-hard-413-abort}
|
|
1171
1172
|
|
|
1172
|
-
**Strike coupling.** A grinder fire bumps the engine's `turnErrors` — the same internal counter cycle detection feeds — so an overflow counts toward the strike streak that ends a runaway loop at 500 (or 508 if the crossing strike was a detected cycle). This is the pressure that keeps self-curation the path of least resistance. {§grinder-strike-coupling} **
|
|
1173
|
+
**Strike coupling.** A grinder fire bumps the engine's `turnErrors` — the same internal counter cycle detection feeds — so an overflow counts toward the strike streak that ends a runaway loop at 500 (or 508 if the crossing strike was a detected cycle). This is the pressure that keeps self-curation the path of least resistance. {§grinder-strike-coupling} **Every compaction strikes — including turn 0/1.** There is no soft exemption: a fold is a fold; the model gets three tries (`maxStrikes`), and three compactions running strike it out. The compacted packet is necessarily slightly heavier than nothing (folded rows still cost their coordinate line), so overflow is never "impossible" — a model that refuses to distill/fold/kill can genuinely strike out. {§grinder-compaction-strikes}
|
|
1173
1174
|
|
|
1174
|
-
**What the model sees.**
|
|
1175
|
+
**What the model sees.** The overflow is a terse `op='error'` log row — a status code and the canonical term, `413 Budget Overflow`, no mechanism vocabulary ("layer," "grinder," "reclaim") and no advice (the packet teaches recovery, not the row). It is minted *before* the rebuild, so its derived `log:///<coord>` pointer surfaces in the `errors` section (§telemetry) THIS turn — at strike 1, not a turn late. The budget readout (§tokenomics) — turn and entry weights — is the diagnostic surface; the model diagnoses the cause the engine can't attribute. Because error rows are grinder-exempt (below), successive overflows stack into a visible recurrence trail the model reads to break a spiral. Per the gamification policy (§telemetry), the *strike* the overflow triggers stays engine-internal; the model sees the error rows, never the accounting. {§grinder-overflow-error-row}
|
|
1175
1176
|
|
|
1176
1177
|
**Rationale.** The model owns curation (§tokenomics); the grinder is the exceptional backstop. It only *folds* — reversibly — the prior turn's render; nothing is deleted, so the model can OPEN it back and log history stays intact. Rummy's own spec described clearing log *bodies*, but its code instead folded the prior turn whole — because body-clearing is destructive (it deletes the read result) and bespoke. The code was the lesson; plurnk follows it.
|
|
1177
1178
|
|
|
@@ -1232,7 +1233,7 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
|
|
|
1232
1233
|
type PacketSection = {
|
|
1233
1234
|
name: string; // stable id: definition, tools, schemes, system-policy, project-policy, budget, prompt, errors, log, git, requirements — or a plugin's own
|
|
1234
1235
|
slot: "system" | "user"; // the prompt-cache boundary; system-slot sections build the cache-stable system message
|
|
1235
|
-
header: string | null; // "## Plurnk
|
|
1236
|
+
header: string | null; // "## Plurnk Service X", or null (definition renders verbatim)
|
|
1236
1237
|
content: string; // rendered markdown — what the model saw
|
|
1237
1238
|
tokens: number; // measured render-weight
|
|
1238
1239
|
};
|
|
@@ -1247,7 +1248,7 @@ type Packet = {
|
|
|
1247
1248
|
|
|
1248
1249
|
The wire projection (`PacketWire.renderSlot`) groups sections by slot into the system + user ChatMessages; the digest re-renders the same stored sections byte-for-byte.
|
|
1249
1250
|
|
|
1250
|
-
**Prompt as a first-class entry.** Each loop's prompt is written on loop start as a plurnk-origin `EDIT` against `plurnk:///prompt/<loop_id>` (indexable, body channel, text/markdown). At render time the current loop's prompt
|
|
1251
|
+
**Prompt as a first-class entry.** Each loop's prompt is written on loop start as a plurnk-origin `EDIT` against `plurnk:///prompt/<loop_id>/<N>` (indexable, body channel, text/markdown). At render time the **Active User Prompts** section materializes **every** prompt the current loop holds, oldest first — typically one, but an active loop admits injected prompts, all shown in order. The section is the OPPOSITE of the errors section: bare HEREDOC bodies, no meta/link line — the heredoc fence (each prompt's own `plurnk://prompt/<loop>/<N>` address) IS the link. A prompt over `PLURNK_PROMPT_PREVIEW_CHARS` renders a `[ Prompt exceeds preview limit. Full content: <addr> ]` pointer instead of its body (the model OPENs/READs the entry to see it whole — never lost). The entry itself stays READ/FOLD-able like any other. The foisted `EDIT`'s **log row is folded by default** (`expanded=0`): the prompt body already lives in the Active User Prompts section, so the log keeps the action for forensics while collapsing the duplicate body, re-OPENable like any fold (§open-fold). {§prompt-fold}
|
|
1251
1252
|
|
|
1252
1253
|
**The entry catalog.** The catalog is the **complete, unranked directory** of what a session holds, served by `FIND(scheme:///**)` — one per-scheme array, queried on demand, not a single materialized entry (there is no `plurnk:///manifest.json`; the per-scheme arrays replaced it). Built in the schemes layer (`_entry-manifest.catalogRowsFor`); a per-turn derivation pump (`maintainDerivations`) refreshes the deep channels the rows report. A scheme's array is **every entry it holds, in no relevance order**, each `{ path, seconds?, tags?, channels: { <uri>: { mimetype, tokens, lines } } }` — every channel keyed by the URI the model READs (the default channel by the bare path, a non-default by `path#channel`), so it reaches a channel without guessing. `tags` is present only when the entry carries `entry_tags` — its own categorization, surfaced so the model can `FIND` by tag. The model ranks and filters the catalog itself by querying it (task-aware); the catalog never ranks for it — the instant it did, it would be an index again. `tokens` is the provider's live count recounted at render, `lines` the content extent from `Mimetypes.process().totalLines`. The catalog never lists itself. {§packet-catalog}
|
|
1253
1254
|
|
|
@@ -1268,24 +1269,29 @@ The `log` section is the durable audit; the `errors` section surfaces both — t
|
|
|
1268
1269
|
**Plurnk-service rendering:**
|
|
1269
1270
|
|
|
1270
1271
|
- `budget` per §tokenomics: turn-weight and heaviest-entries tables with `tokenCeiling`/`tokenUsage`/`tokensFree`.
|
|
1271
|
-
- **
|
|
1272
|
-
- **
|
|
1273
|
-
- **
|
|
1274
|
-
- **Gamification policy (rummy precedent, plugins/error/error.js).** The model sees errors that **happened** — its actions failed, its emission didn't parse, its ops were truncated. The model does NOT see the engine's accounting *about* errors: strike streaks, cycle detection, sudden-death thresholds, no-ops bookkeeping. Surfacing internal state creates a gamification surface where the model optimizes for engine metrics (manufacturing a clean turn to reset the strike counter, e.g.) instead of the task. Engine bookkeeping drives abandonment silently; the model just sees its actual failures.
|
|
1272
|
+
- **One uniform error channel.** EVERY failure — a failed action, an actionless parse failure, and every engine-rail failure (budget overflow, max-commands, the idle/premature steers) — is an `op='error'` `log_entries` row with `status_rx ≥ 400`. No per-category handling, no bespoke ephemeral relationship. The `errors` section is a derived index over those rows (the current turn and the immediately-prior one): one terse `<status> log:///<coord>` link per row, nothing else. The term and full detail live on the foldable row, READ via the link. {§telemetry-uniform-error-channel}
|
|
1273
|
+
- **Terse rows.** An error row's body is a status code and the canonical term — `Budget Overflow`, `Max Commands Exceeded`, `Idle Turn`, `Premature Termination` — never prose, hints, or advice. The packet (requirements, grammar) teaches recovery; the row names the fault. Letting the model infer what to do from the fact (and the log) beats handing it instructions it will second-guess.
|
|
1274
|
+
- **Notices** — the few events that are NOT log rows (a provider's `grammar_unenforced`, which points at the model's own emission via a content-offset) render one terse line under `## Plurnk Service Errors` by their typed `position`, never a JSON dump. The notice buffer drains on read — each appears on exactly one packet. {§telemetry-drain-on-read}
|
|
1275
|
+
- **Gamification policy (rummy precedent, plugins/error/error.js).** The model sees errors that **happened** — its actions failed, its emission didn't parse, its ops were truncated, it overflowed the window. The model does NOT see the engine's accounting *about* errors: strike streaks, cycle detection, sudden-death thresholds, no-ops bookkeeping. Surfacing internal state creates a gamification surface where the model optimizes for engine metrics (manufacturing a clean turn to reset the strike counter, e.g.) instead of the task. Engine bookkeeping drives abandonment silently; the model just sees its actual failures.
|
|
1275
1276
|
|
|
1276
|
-
**The error
|
|
1277
|
+
**The error rows (one channel) + the only non-log notices:**
|
|
1277
1278
|
|
|
1278
|
-
|
|
|
1279
|
+
| failure | row | status |
|
|
1279
1280
|
|---|---|---|
|
|
1280
|
-
|
|
|
1281
|
-
|
|
|
1282
|
-
|
|
|
1283
|
-
|
|
|
1284
|
-
|
|
|
1281
|
+
| parse failure | `op='error'`, origin `model`, source `grammar`; body = parser message + content-offset `line:col` | 400 |
|
|
1282
|
+
| action failure | the failed op's own row (the scheme set `status_rx ≥ 400`); body = the scheme's error | 4xx/5xx |
|
|
1283
|
+
| budget overflow | `op='error'`, origin `plurnk`, source `rail`; body = `Budget Overflow: newest log items automatically FOLDed` | 413 |
|
|
1284
|
+
| max commands exceeded | `op='error'`, origin `plurnk`, source `rail`; body = `Max Commands Exceeded` | 429 |
|
|
1285
|
+
| idle turn / premature termination | `op='error'`, origin `plurnk`, source `rail`; body = `Idle Turn` / `Premature Termination` | 409 |
|
|
1285
1286
|
|
|
1286
|
-
|
|
1287
|
+
| notice `kind` | Source | Position |
|
|
1288
|
+
|---|---|---|
|
|
1289
|
+
| `grammar_unenforced` | (provider, forwarded) GBNF-filter divergence — the model's bytes diverged from the transported grammar | content-offset into the model's emission |
|
|
1290
|
+
| `embed_progress` | derivation-pump milestone (§mimetype-surface); `level: info`, never in the errors section | none |
|
|
1291
|
+
|
|
1292
|
+
**Severity on the wire (`level`, required — grammar 0.74.29+).** Every `TelemetryEvent` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site — severity is meaning the producer owns, not something the client re-derives by pattern-matching the open `kind` vocabulary. Service mappings: every error log row is `error` (an error is an error); a forwarded `grammar_unenforced` carries the producer's own level (defaulted to `warn` only when the producer predates the field); `embed_progress` is `info`, a progress note that never reaches the errors section. Clients color straight off `level`. {§telemetry-event-level}
|
|
1287
1293
|
|
|
1288
|
-
Strike accounting, cycle detection, sudden-death thresholds, and no-ops bookkeeping stay engine-internal — they drive abandonment silently per the gamification policy.
|
|
1294
|
+
Strike accounting, cycle detection, sudden-death thresholds, and no-ops bookkeeping stay engine-internal — they drive abandonment silently per the gamification policy. EVERY error — a failed action, an actionless parse failure, and every engine-rail failure (budget overflow, max-commands, the idle/premature steers) — is a LOG ITEM (`log:///<coord>`, `op='error'`, `status_rx ≥ 400`), foldable and re-OPENable, with its terse term on the row. The `errors` section surfaces a derived pointer to each. There is **no bespoke `error://` scheme** and no ephemeral per-category error buffer: errors live in the log, addressable + curatable like any row — not a separate namespace, not a drain-on-read side channel. {§telemetry-no-error-scheme}
|
|
1289
1295
|
|
|
1290
1296
|
**Client surface.** Engine NOTICES broadcast live via the `telemetry/event` WS notification — same envelope as the model's drained copy (`{ source, kind, level, message?, position?, …kind-specific }` per the grammar's `TelemetryEvent` schema), the moment they land, scoped to the loop's session (a `grammar_unenforced` snippet in a debug panel, a session timeline). ERRORS do not broadcast on this surface: they are log rows, and the client reads them the same way the model curates them — `log.read` / the `log/entry` notification, the durable log. {§telemetry-telemetry-event-notify}
|
|
1291
1297
|
|
|
@@ -1293,13 +1299,13 @@ Strike accounting, cycle detection, sudden-death thresholds, and no-ops bookkeep
|
|
|
1293
1299
|
|
|
1294
1300
|
### §tools user.tools — the capability sheet
|
|
1295
1301
|
|
|
1296
|
-
The tools capability lines render **titleless**, directly under the `definition` (plurnk.md) section — the examples flow on from plurnk.md with no separate header — and **above** `## Plurnk
|
|
1302
|
+
The tools capability lines render **titleless**, directly under the `definition` (plurnk.md) section — the examples flow on from plurnk.md with no separate header — and **above** `## Plurnk Service Requirements`, so the model sees what it can *do* before the rules it must follow. Each enabled capability contributes one line via `Engine.#collectTools`; the section is omitted when nothing is enabled. {§tools-capability-sheet}
|
|
1297
1303
|
|
|
1298
1304
|
**Contributors: the wired executor tags.** Each available executor tag *with an example* contributes ONE line — its canonical usage — via the shared `teachingLine` (identical shape to the scheme directory, §schemes); its doc is materialized at `plurnk://docs/<tag>.md` and discovered via the turn-1 `FIND(plurnk://docs/**)` foist, not linked inline (#270). A tag with no example contributes nothing; `PLURNK_DOCS_EXCLUDE` drops a named tag's line + doc. The boot `ExecutorRegistry` probes availability per tag, retiring the model's blind `<<EXEC[sh]…`.
|
|
1299
1305
|
|
|
1300
1306
|
### §schemes user.schemes — the scheme directory
|
|
1301
1307
|
|
|
1302
|
-
A `## Plurnk
|
|
1308
|
+
A `## Plurnk Service Schemes` section renders in the system slot **after the definition (plurnk.md — grammar + imperatives) and the tools sheet** — a terse directory of the scheme families available this session, so the model knows what URI schemes exist before it acts. Each scheme that ships a `manifest.example` contributes ONE line — its canonical usage (no scheme prefix; the example self-documents). The doc is NOT linked inline (#270) — it is materialized at `plurnk://docs/<scheme>.md` and discovered via the turn-1 `FIND(plurnk://docs/**)` foist, keeping the raw packet free of doc links. The in-tree core schemes author their depth in `docs/<name>.md` (loaded at boot, shipped with the package); daughter schemes ship `manifest.documentation`. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls, via the same `teachingLine` as the tools sheet (§tools). A scheme with no example (provisional) is omitted; `PLURNK_DOCS_EXCLUDE` drops a named scheme's line + doc. {§schemes-directory}
|
|
1303
1309
|
|
|
1304
1310
|
### §inject system.inject — the operator injection
|
|
1305
1311
|
|
|
@@ -1307,13 +1313,13 @@ When `PLURNK_PACKET_INJECT` names a readable markdown file, its content renders
|
|
|
1307
1313
|
|
|
1308
1314
|
### §policy system.policy — the client's policy injection
|
|
1309
1315
|
|
|
1310
|
-
Two sections ride the system slot **below the operator notes, above budget**: `## Plurnk
|
|
1316
|
+
Two sections ride the system slot **below the operator notes, above budget**: `## Plurnk Service Policy` from `PLURNK_POLICY` (default `~/.plurnk/AGENTS.md`) and `## Project Policy` from `PLURNK_PROJECT` (default `<projectRoot>/AGENTS.md`, resolved relative to the session root). AGENTS.md is **policy** — the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. Reference/scratch docs are NOT policy — they ride `PLURNK_MD_*` (materialized as READ-able entries, §operator-config), which is where the dev-notes AGENTS.md used to hold belong. {§policy-sections}
|
|
1311
1317
|
|
|
1312
1318
|
**The scheme self-doc contract.** `example` is the hot-path one-liner; `documentation` is the deep doc — the exact shape execs already use (`example` + `documentation`). `SchemeRegistry.teach()` renders the directory; `docEntries()` materializes the docs (per loop.run, alongside the operator docs). `documentation` rides a service-side `SchemeManifest` extension until plurnk-schemes#25 lands it in the contract.
|
|
1313
1319
|
|
|
1314
1320
|
### §requirements The requirements section — static per-turn rules
|
|
1315
1321
|
|
|
1316
|
-
Rendered at the END of the user packet under `## Plurnk
|
|
1322
|
+
Rendered at the END of the user packet under `## Plurnk Service Requirements` {§requirements-requirements-render-last} — closest to the assistant turn so the contract the model has to honor is the most recent text it sees. The header is omitted entirely when the requirements string is empty. {§requirements-requirements-omitted-when-empty} Contains rules the grammar block doesn't cover (canonical example: "Conclude the loop with `<<SEND[200]:answer:SEND`"). The op syntax leads the section. PLAN is mandated unconditionally by plurnk.md §Imperatives (grammar 0.70 requires every turn to lead with `<<PLAN`), so the service injects no separate plan directive here.
|
|
1317
1323
|
|
|
1318
1324
|
**Sourcing:** caller supplies the string via `runLoop({ requirements })` / `runTurn({ requirements })`. Plurnk-service exposes `PATHS.defaultRequirements` (resolves `PLURNK_REQUIREMENTS` env → in-package `requirements.md`). No DB cascade — same string every turn.
|
|
1319
1325
|
|
package/dist/core/Engine.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ type DispatchContext = {
|
|
|
19
19
|
sequence: number;
|
|
20
20
|
origin: WriterTier;
|
|
21
21
|
onDispatch?: (logEntryId: number) => void;
|
|
22
|
+
prematureRefusal?: boolean;
|
|
22
23
|
};
|
|
23
24
|
type DispatchResult = {
|
|
24
25
|
status: number;
|
|
@@ -134,6 +135,7 @@ export default class Engine {
|
|
|
134
135
|
resolveProposal(logEntryId: number, resolution: ProposalResolution): void;
|
|
135
136
|
pendingProposalIds(): number[];
|
|
136
137
|
hasActiveLoopForRun(runId: number): Promise<boolean>;
|
|
138
|
+
warmSessionDerivations(sessionId: number): Promise<void>;
|
|
137
139
|
inject(runId: number, prompt: string): Promise<{
|
|
138
140
|
loopId: number;
|
|
139
141
|
turnSeq: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAA0G,MAAM,wBAAwB,CAAC;AAMtK,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAiB,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;AAa9C,OAAO,KAAK,EAAkB,UAAU,EAAuB,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACpG,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"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"}
|