@plurnk/plurnk-service 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +1 -1
  2. package/SPEC.md +22 -17
  3. package/dist/content/edited-span.js +1 -1
  4. package/dist/content/edited-span.js.map +1 -1
  5. package/dist/content/matcher.js +2 -2
  6. package/dist/content/matcher.js.map +1 -1
  7. package/dist/content/mimetype-binary.js +1 -1
  8. package/dist/content/mimetype-binary.js.map +1 -1
  9. package/dist/core/Engine.d.ts.map +1 -1
  10. package/dist/core/Engine.js +51 -5
  11. package/dist/core/Engine.js.map +1 -1
  12. package/dist/core/Engine.sql +11 -4
  13. package/dist/core/packet-wire.d.ts.map +1 -1
  14. package/dist/core/packet-wire.js +53 -25
  15. package/dist/core/packet-wire.js.map +1 -1
  16. package/dist/digest/Digest.d.ts +2 -0
  17. package/dist/digest/Digest.d.ts.map +1 -1
  18. package/dist/digest/Digest.js +9 -3
  19. package/dist/digest/Digest.js.map +1 -1
  20. package/dist/schemes/Exec.d.ts +1 -0
  21. package/dist/schemes/Exec.d.ts.map +1 -1
  22. package/dist/schemes/Exec.js +3 -2
  23. package/dist/schemes/Exec.js.map +1 -1
  24. package/dist/schemes/File.d.ts.map +1 -1
  25. package/dist/schemes/File.js +11 -3
  26. package/dist/schemes/File.js.map +1 -1
  27. package/dist/schemes/Log.d.ts.map +1 -1
  28. package/dist/schemes/Log.js +14 -12
  29. package/dist/schemes/Log.js.map +1 -1
  30. package/dist/schemes/Log.sql +3 -3
  31. package/dist/schemes/Prompt.d.ts.map +1 -1
  32. package/dist/schemes/Prompt.js +2 -1
  33. package/dist/schemes/Prompt.js.map +1 -1
  34. package/dist/schemes/_entry-ops.d.ts +1 -0
  35. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  36. package/dist/schemes/_entry-ops.js +19 -7
  37. package/dist/schemes/_entry-ops.js.map +1 -1
  38. package/package.json +16 -16
package/README.md CHANGED
@@ -6,7 +6,7 @@ LLM agent runtime engine. Consumes [plurnk-grammar](https://github.com/plurnk/pl
6
6
 
7
7
  Grammar ops: `PLAN` reason · `READ`/`EDIT` files · `FIND` search · `EXEC` run shell/code · `SEND` message or conclude · `COPY`/`MOVE`/`KILL` manage · `OPEN`/`FOLD` curate its own context.
8
8
 
9
- Over schemes: `file://` project files · `exec://` command output · `http(s)://` web fetch · `worker://` sibling agent runs (spawn / fork / message) · `known://` scratch · `log://` own history.
9
+ Over schemes: `file://` project files · `exec://` command output · `http(s)://` web fetch · `worker://` scratch + sibling agent runs (commons/own-space/spawn/fork/message) · `prompt://` the task frame · `skill://` bundled reference · `log://` own history.
10
10
 
11
11
  ## Loop model
12
12
 
package/SPEC.md CHANGED
@@ -351,7 +351,7 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
351
351
 
352
352
  - **Log speaks the universal query contract** {§log-uniform-query} — `FIND(log://…)` works like every scheme's FIND (the jumbo model ran the canon-documented `FIND(log:///**):#…#` six times into a bare 501 — log was the one scheme outside the universal paradigm, by accident not decision). Candidates are the worker's rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}); each is projected EXACTLY as READ shows it (the rx unwrap — FIND must match what the model can retrieve); the shared `Matcher.matchCandidates` ({§find-source-agnostic}) applies any content dialect; results are catalog-shaped items keyed `log:///loop/turn/seq/OP` with `{mimetype, tokens, lines}`, and the fan-out retargets per-row READs so `READ(log://…):matcher` composes identically to entries (#286). A tag signal filters candidates by the model's own region tags ({§log-region-tagging}); log rows carry no symbol channels (`@graph` 501, an honest absence). `~semantic` is an HONEST 501 until the pump embeds log rows under the same uniform rules as entries (no selection heuristics — protocol-ack dust self-filters at the FTS-narrowing stage); storage stays the event stream (the Q3/Option-B decision: uniform QUERY contract, honest distinct storage).
353
353
  - **The content matcher is source-agnostic** {§find-source-agnostic} — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND/READ with every content dialect works uniformly across schemes BY CONSTRUCTION — `EntryFind` and `Log.find` run the ONE shared primitive rather than re-implementing per scheme. This is the query-layer half of the log-uniformity decision (Q3, Option B): log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
354
- - **Line-oriented matching is the tent pole; the selection signal is additive** {§matcher-selection-signal} — a pattern match returns the SOURCE LINE containing it, with its line number (`42:\tI bought Alice some flowers`, never `1:\tAlice`): the line is the universal coordinate the whole op-algebra composes on (FIND spans → READ delivers → EDIT mutates), and extraction dialects admit NO exception (owner ruling — a bare value has no coordinate and silently breaks the composition). The degenerate case — a MINIFIED single-line document, where "the line" is the whole file — is answered with SIGNAL on the FIND row, not a semantics change: a matcher READ's fan-out WRITES its internal FIND as a selection-summary row (sequence-first, exactly as if the model had FINDed then READ), whose rx carries one result item per HIT with `matchSpan` and `matchPath` (the hit's canonical dialect coordinate, e.g. `$['users'][0]['name']`, when the dialect provides one). Deliveries stay span-DEDUPED (#286 — N hits on one source line deliver that line once, no identical-row noise); the summary row is what tells the model its query hit N times and WHERE (run30: two hits indistinguishable from failure; 17 retries, 508). The teaching half is grammar's canon (grammar#56).
354
+ - **Line-oriented matching is the tent pole; the selection signal is additive** {§matcher-selection-signal} — a pattern match returns the SOURCE LINE containing it, with its line number (`42:I bought Alice some flowers`, never `1:Alice`): the line is the universal coordinate the whole op-algebra composes on (FIND spans → READ delivers → EDIT mutates), and extraction dialects admit NO exception (owner ruling — a bare value has no coordinate and silently breaks the composition). The degenerate case — a MINIFIED single-line document, where "the line" is the whole file — is answered with SIGNAL on the FIND row, not a semantics change: a matcher READ's fan-out WRITES its internal FIND as a selection-summary row (sequence-first, exactly as if the model had FINDed then READ), whose rx carries one result item per HIT with `matchSpan` and `matchPath` (the hit's canonical dialect coordinate, e.g. `$['users'][0]['name']`, when the dialect provides one). Deliveries stay span-DEDUPED (#286 — N hits on one source line deliver that line once, no identical-row noise); the summary row is what tells the model its query hit N times and WHERE (run30: two hits indistinguishable from failure; 17 retries, 508). The teaching half is grammar's canon (grammar#56).
355
355
 
356
356
  `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).
357
357
 
@@ -503,7 +503,7 @@ Rules:
503
503
 
504
504
  1. Fragment-less paths target the scheme's `defaultChannel`. {§channel-selection-fragmentless-targets-default-channel}
505
505
  2. Paths with a fragment target the named channel. {§channel-selection-fragment-selects-named-channel}
506
- 3. Unknown channel name → 400. {§channel-selection-unknown-channel-400}
506
+ 3. Unknown channel name → 400, carrying the fact that names the tried fragment and the declared universe (`no channel #results at exec:///run/abc; channels: stdout, stderr`) — one miss teaches the topology. {§channel-selection-unknown-channel-400}
507
507
  4. Schemes without `defaultChannel` reject fragment-less EDIT/READ.
508
508
  5. Non-default channel EDIT requires entry to exist (404 if absent); default-channel EDIT creates. {§channel-selection-fragment-on-nonexistent-404}
509
509
  | URI | Channel |
@@ -558,8 +558,9 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
558
558
  - Writes body; `body: null` clears. {§edit-null-clears}- Returns `{ status: 201, entryId }` for new entries; `{ status: 200, entryId }` for content updates. {§edit-status-201-200}
559
559
  - A write that changes nothing — identical content and no new tag — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's no-op (§open-fold). {§edit-noop-304}
560
560
  - Tags from `signal[]` apply additively via `entry_tags` (scheme may vary). {§edit-tags-additive}
561
+ - **A markerless EDIT is CREATE-ONLY — there is no easy-clobber path on an existing entry.** {§edit-marker-required-on-existing} A `<L>` marker scopes an EDIT to a range; without one, the body becomes the entry's WHOLE content — legitimate and required for a fresh entry (nothing exists to scope into), but on an EXISTING entry a missing marker is refused **400**, never a silent full replace. A deliberate full rewrite states that intent explicitly: `<1,-1>` resolves through the ordinary marker math to the same whole-content replacement, so the capability isn't lost, only the omission. (#571 — run126: a misplaced `<356>` landed inside the body rather than the marker slot, so the EDIT parsed markerless and silently replaced a 1,693-line file with 2; the model's own subsequent reads told it the entry now had 2 lines, twice, and it never connected the fact to its own edit before reporting false success.) This closes the omission's blast radius without capping legitimate content — the same rewrite is always available, it can just never happen by accident.
561
562
 
562
- A `file:///` member EDIT diverges from this immediate-write contract: it diffs against the entry snapshot (the body channel, never a fresh disk read) and **proposes** (202) a disk write that lands via a compare-and-swap on accept. See §membership-edit-write-cas and the proposal lifecycle §proposal.
563
+ A `file:///` member EDIT diverges from this immediate-write contract: it diffs against the entry snapshot (the body channel, never a fresh disk read) and **proposes** (202) a disk write that lands via a compare-and-swap on accept. See §membership-edit-write-cas and the proposal lifecycle §proposal. The marker-required rule above applies identically here — an existing file is never markerlessly replaced.
563
564
 
564
565
  ### §read READ
565
566
 
@@ -577,9 +578,9 @@ OPEN/FOLD operate on the **log** (`log:///`) — the model's context-curation su
577
578
 
578
579
  ### §jsonplurnk The Log's wire format
579
580
 
580
- The `## Log` section renders as a fenced `jsonplurnk` block — a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: each `body` value, when present, is a raw HEREDOC (`<<:::TAG … :::TAG`, TAG = the entry's target/log URI), rendered verbatim (numbered for text, tree-navigable verbatim), never 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 (the plurnkdown linter's transform). Each entry's fold state is a self-documenting `display` field (grammar-ratified #437 — `display:none` mirrors CSS, `folded`/`open` echo the FOLD/OPEN ops): `"display":"none"` (no body), `"folded"` (a body exists but is hidden, still weighable), `"open"` (body shown, heredoc present). The block's leading Note defines the carve-out AND the token semantics in-packet (#466 — a number the model can see states its meaning where it appears, never in a doc it can't): `tokens` is the ruler-weight of the row's body in this packet — the room it takes (what OPEN adds, what FOLD saves); a FIND's `itemsTokenTotal` is the ruler-weight of the matched entries themselves (the room READing them takes) — 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, bodyless-0-token items, the explicit fold state). This is the Log's realization of the packet-wide plurnkdown house style — the whole outbound packet is one coherent document, log data stays JSON housed in a fence. {§jsonplurnk}
581
+ The `## Log` section renders as a fenced `jsonplurnk` block — a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: each `body` value, when present, is a raw HEREDOC (`<<:::TAG … :::TAG`, TAG = the entry's target/log URI), rendered verbatim (numbered for text, tree-navigable verbatim), never 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 (the plurnkdown linter's transform). Each entry's fold state is a self-documenting `display` field (grammar-ratified #437 — `display:none` mirrors CSS, `folded`/`open` echo the FOLD/OPEN ops): `"display":"none"` (no body), `"folded"` (a body exists but is hidden, still weighable), `"open"` (body shown, heredoc present). The block is data only no prose leads the fence. The numbers' semantics: `tokens` is the ruler-weight of the row's body in this packet — the room it takes (what OPEN adds, what FOLD saves); a FIND's `itemsTokenTotal` is the ruler-weight of the matched entries themselves (the room READing them takes) — 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, bodyless-0-token items, the explicit fold state). This is the Log's realization of the packet-wide plurnkdown house style — the whole outbound packet is one coherent document, log data stays JSON housed in a fence. {§jsonplurnk}
581
582
 
582
- The opening fence length is **dynamic**: one backtick longer than the longest backtick run in any body (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:\t` numbering that incidentally keeps text bodies off column 0. {§jsonplurnk-dynamic-fence}
583
+ The opening fence length is **dynamic**: one backtick longer than the longest backtick run in any body (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. {§jsonplurnk-dynamic-fence}
583
584
 
584
585
  ### §model-entry The model's own emission, mirrored back
585
586
 
@@ -593,6 +594,8 @@ The worker's **first** model row is exceptional: a born-OPEN turn-0 **exemplar**
593
594
 
594
595
  **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** (#382): the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). The emission also survives verbatim in the `model` mirror. A **failed** OPEN/FOLD (bad target, bad range) 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. {§fold-open-meta-operations}
595
596
 
597
+ **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 — it is exactly the OPEN/FOLD case one step later. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its emission survives in the `model` mirror. This closes a self-growing curation trap: a floor model that KILLs log rows to reclaim budget otherwise accumulates one bodyless-but-~130-char tombstone per kill, and per-row KILL can never shrink the log (each clear leaves a new receipt) — run61 reached ~2000 tombstones, 95% of the packet. 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. {§kill-log-receipt-suppressed}
598
+
596
599
  ### §copy COPY (engine-orchestrated)
597
600
 
598
601
  AST: `{ op: "COPY", target (source), body (destination), signal: tags | null, lineMarker? }`.
@@ -1166,7 +1169,7 @@ Each entry: question, answer, rationale, migration path.
1166
1169
  - **Provider tokens, stored at write.** `provider.countTokens` is the source of truth; `entry_channels.tokens` (via `_entry-crud`) and `log_entries.tokens` (via `Dispatcher.#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}
1167
1170
  - **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-weigh the rendered packet; render-weight is the accurate measure. {§tokenomics-render-weight-budget}
1168
1171
  - **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 fold unit, and the rail folds only the **newest** (§grinder); the model sees which turns are fat and can FOLD ahead of the rail. {§tokenomics-turn-totals}
1169
- - **Heaviest entries.** A second table lists the five heaviest log entries by their **body weight — the same number the row's own `tokens` shows** (what a FOLD saves; #466: the budget and the log never disagree about one row), each by its `log:///<coord>/<op>` handle — the FOLD targets behind the turn weight. A bodyless row is no FOLD target and never ranks. The handle carries the turn, so the two tables interlock. {§tokenomics-largest-entries}
1172
+ - **Heaviest entries.** A second table lists the five heaviest log entries by their **body weight — the same number the row's own `tokens` shows** (what a FOLD saves; #466: the budget and the log never disagree about one row), each by its `log:///<coord>/<op>` handle — the FOLD targets behind the turn weight. A row ranks only when a FOLD would actually reclaim it: a bodyless row has nothing to fold, an already-folded row is already reclaimed (its `tokens` price an OPEN, not a FOLD), and the current loop's foisted preview is refused outright (§prompt-fold-illegal) — the list never advertises a lever the law refuses or the state has already pulled. The handle carries the turn, so the two tables interlock. {§tokenomics-largest-entries}
1170
1173
  - **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}
1171
1174
  - **The window is a partition, never a fraction.** the window and both reserves are **provider-owned** (#507, owner-ruled): `provider.contextWindow` (probed/declared in the provider tier), `provider.reasoningReserve` and `provider.completionReserve` (ingested or `PLURNK_PROVIDERS_*`-pinned there, percent or absolute). A null window or null reserves is genuinely-unknown — nobody chose an envelope — and is treated as **NO-CAP** — the prompt is unbounded, the budget and ceiling resolve to null and the gauge omits its headline — rather than let numbers nobody chose silently stand in for unknown physics; a probe blip must degrade to no-cap, never crash the loop {§tokenomics-window-unpollable-deliberate}) splits **without remainder**: `promptBudget = min(operatorCap, provider.contextWindow) − reasoningReserve − completionReserve − PLURNK_SERVICE_SAFETY` is what the service may send — the operator's `PLURNK_PROVIDERS_CONTEXT_WINDOW` pin (alias-scoped else bare) is CORE's log-budget cap (#528): construction strips it so the provider reports its NATURAL window, reserves derive from that nature (a tighter log never throttles how much the model may think or say), and the cap tightens the PROMPT alone; a pin over an UNPOLLABLE window (#419) declares the window itself — no separate nature exists, reserves derive from the declaration — `max_tokens = reasoningReserve + completionReserve` is the generation envelope passed on every `generate({maxTokens})` when the reserves are known, and `SAFETY` — core's ONE remaining partition knob, the ruler's own packing margin — covers chat-template overhead no content counter sees. The retired `PLURNK_SERVICE_{CONTEXT_WINDOW,REASONING,COMPLETION}` names fail hard at boot naming their provider-tier successors. The prompt ceiling is **derived, never set**: a settable ceiling lets policy contradict physics, and a fractional one budgets the prompt against the window while *forgetting the response lives there too* (at 0.9 × 49152, any emission past ~4.9k overflowed gemma with a perfectly honest ruler). Reserves exceeding the window (`promptBudget ≤ 0`) are a configuration contradiction and fail hard — post-migration its one cause is pinned absolute reserves over a detected window; percent reserves derive and cannot contradict. When native reasoning is on, llama-server ignores per-request numeric budgets — the serving box's `--reasoning-budget` launch flag must equal the alias's resolved reasoning reserve, and the service warns at boot when it cannot verify that coupling. The LOCAL example partition (turboderp suffix, 78848 − 4096 − 8192 − 1024) yields exactly 65536 prompt tokens; the bare cloud defaults yield a large decode envelope the backend self-clamps. {§tokenomics-window-partition} **The partition is PER ALIAS** (#352): each knob resolves `PLURNK_SERVICE_<KNOB>_<alias>` over the bare fallback (providers' `scopeEnvToAlias`), scoped by the alias that produced the turn's provider (the service's own provider→alias side-table, falling back to the active boot alias). BARE defaults are cloud-generous — the generation envelope is a large `max_tokens` the backend self-clamps to its true output limit (cloud APIs accept and silently clamp; none expose a max-output field, so generous-and-clamp is the honest posture, and a cloud reasoner burning ~16k on thought finishes its DSL instead of dying at `finish=length`). LOCAL (llama-server) aliases MUST keep a measured envelope — `n_predict` is honored to the context wall, so an unbounded decode wall-runs (providers#10, the cap doctrine's origin); a local alias whose partition contradicts its real window fails HARD at build time, naming the per-alias knobs to set.
1172
1175
  - **Derivation is off the hot path; search is never degraded by it.** The per-turn derivation pump and the workspace warm run on a background chain (serialized, drained at daemon stop, failures logged) — **a turn never waits on an embedding** (a 2-CPU container CPU-embedding a 335-entry ingest starved every loop ~28min). Full fidelity survives the move on both fusion halves: the **keyword half indexes at the write** (plain string→FTS, no handler invoked — a cold workspace's first query narrows over everything ever written) {§semantic-fts-at-write}, and a `~` query **derives its own FTS-narrowed candidate slice inline** at dispatch (bounded, cap-telemetered) — ranking only ever scores the narrowed set, so warming exactly that slice is bit-identical to a fully-warm corpus, from turn 1, on any hardware {§semantic-cold-query-full-fidelity}. {§derivation-off-hot-path}
@@ -1246,7 +1249,9 @@ The CAS is the **hard backstop**, at the moment of writing, on every accept path
1246
1249
  - **The hard overflow is a RECOVERY TURN first** {§grinder-hard-413-recovery} — (Q4, owner ruling: recoverable strike, NO margin). The overflow lives in foldable HISTORY the model owns, and the grinder never touches history (§grinder-layer1-rollback) — so the first hard overflow, when the packet is over the POLICY ceiling but still within PHYSICS (the provider's real window minus the decode reserve), is sent ANYWAY, once: a minted `budget_overflow` steer states the fact, the remedy (KILL/FOLD history; the budget table lists the heaviest), and the consequence — and the turn counts a strike (`budgetStruck`). The model curates → the next fitting turn clears the grant (a later overflow earns a fresh recovery; chronic overflow still strikes out via the rail). A recovery turn that CONCLUDES is a legitimate 200 — finishing is a way to stop overflowing. **No 95% margin**: the pointer fires at 100% of budget — a margin masks the signal, and the decode is separately reserved.
1247
1250
  - **Hard stop.** A physically-unsendable packet (over the provider's real window too — physics doesn't negotiate), or a SECOND consecutive hard overflow after the recovery turn (the model was told and declined), abandons the loop at **413 Content Too Large** (`engine_loop_set_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}
1248
1251
 
1249
- - **Output truncation states its cause** {§tokenomics-output-truncated} — a `finish=length` turn was guillotined at the decode pool (`REASONING + COMPLETION`, one undifferentiated `max_tokens` — §tokenomics-window-partition), and its parse errors are truncation ARTIFACTS: without the cause stated, the model reads "unclosed block" and fixes syntax forever instead of emitting less (run29: unclamped cloud reasoning + a 9-edit emission vs a 12288 pool; the binding cap was plurnk's own — `completion 12281`). One terse `output_truncated` row (413) leads the artifact rows it explains, naming the cap and distinguishing its two shapes so the model reads the right cause: content cut **mid-op** (a valid prefix dispatched; the parse errors are the severed tail) vs the pool consumed with **nothing emitted** (reasoning ran away — the parse `must begin with PLAN` is an artifact of the empty emission, not a malformed turn). The row states the fact, not a remedy. The parse rows stay — the record never hides — and the partition's bluntness for unclamped cloud reasoning (reasoning-tokens and emission-tokens sharing one pool) is a known limit: sizing REASONING to the model class is the operator lane; a per-API split decode budget is a providers-contract candidate, owner-gated (run52 made it concrete — a cloud reasoner spent the entire 65536 pool on reasoning, emitting zero content, three times).
1252
+ - **Output truncation states its cause** {§tokenomics-output-truncated} — a `finish=length` turn was guillotined at the decode pool (`REASONING + COMPLETION`, one undifferentiated `max_tokens` — §tokenomics-window-partition), and its parse errors are truncation ARTIFACTS: without the cause stated, the model reads "unclosed block" and fixes syntax forever instead of emitting less (run29: unclamped cloud reasoning + a 9-edit emission vs a 12288 pool; the binding cap was plurnk's own — `completion 12281`). One terse `output_truncated` row (413) leads the artifact rows it explains, naming the cap and distinguishing its two shapes so the model reads the right cause: content cut **mid-op** (the severed frame see {§broken-packet-no-dispatch}) vs the pool consumed with **nothing emitted** (reasoning ran away — the parse `must begin with PLAN` is an artifact of the empty emission, not a malformed turn). The row states the fact, not a remedy.
1253
+
1254
+ - **A broken packet dispatches nothing.** {§broken-packet-no-dispatch} A `finish=length` emission that failed to parse (empty, or cut mid-op) is a **broken packet** — structurally incomplete, its parsed "ops" a severed frame, not the model's intent. Core does NOT pass that garbage along: **nothing dispatches**, and the turn is a no-ops **422** strike (so a repeated runaway can't spin as a `102` continue). It still RECORDS through the ordinary error channel — the folded `model` mirror, the `output_truncated` 413, and the parse-error rows — so the model sees why and re-emits next turn (no same-turn re-generate; the existing rail carries recovery). run42: an unclosed `<<PLAN` swallowed a 57,276-char runaway; core had been materializing it as a bogus status-200 `PLAN` op (29k, grinder-exempt) — a budget bomb that gated out the recovery. This is the STRUCTURAL failure (a severed frame), categorically distinct from a **flubbed op** — a well-framed turn (`finish=stop`) whose single op carries a local error still dispatches its valid ops and steers on the bad one (the recovery rail). The gate is `finish=length` + a failed parse: `finish=length` is the provider's definitive "I guillotined this" signal, so the two together mean precisely "truncation severed the frame" — the complete signal, not a heuristic. A deliberate syntax error is not truncation and is correctly left to the recovery rail. The parse rows stay — the record never hides — and the partition's bluntness for unclamped cloud reasoning (reasoning-tokens and emission-tokens sharing one pool) is a known limit: sizing REASONING to the model class is the operator lane; a per-API split decode budget is a providers-contract candidate, owner-gated (run52 made it concrete — a cloud reasoner spent the entire 65536 pool on reasoning, emitting zero content, three times).
1250
1255
 
1251
1256
  - **Fetch-fits-free — the pressure law** {§tokenomics-fetch-fits-free} — under budget pressure, a retrieval larger than the headline's Tokens Free arrives ALREADY FOLDED: the result lands in the next build, the build overflows, and the grinder's one rule folds the newest boundary — which is exactly that result. The model never sees an oversized fetch open, however many times it re-fetches (the read→grind→re-read spiral: run24 on grok, the jumbo fixture on gemma — five turns of narrowing asks, three grind-strikes, 500). The engine's numbers are honest and the grinder is doctrine-correct; the model's ONLY working lever is ordering: FOLD history first (the Heaviest-items table is the target list), then fetch within the room made. The 413 error row states this law verbatim — the signal fires exactly when the lesson applies. Corollary: each turn accrues ~a couple hundred tokens of unavoidable meta (the mirror row, PLAN, budget growth), so a Tokens Free below that accretion is a dead state the NEXT build inherits — conclude or fold before it reaches zero, not at zero.
1252
1257
 
@@ -1334,9 +1339,9 @@ The wire projection (`PacketWire.renderSlot`) groups sections by slot into the s
1334
1339
 
1335
1340
  **Sealed reasoning rides the mirror row.** {§sealed-reasoning-carrier} A provider's ENCRYPTED reasoning — the OpenAI Responses reasoning-item LIST (`[{id, subtype, encrypted: [{data, format}]}]` — a turn can carry N distinct-id items; normalized by the provider tier: id + subtype from the wire, never synthesized) — lands VERBATIM in the model mirror row's `attrs.reasoning` — per turn, on the same `log/entry` broadcast and `readLog` read the client seam already consumes; agui projects one correlated `REASONING_ENCRYPTED_VALUE` span per item (#482). A cross-lane conformance test drives core's real write through agui's real Translator, so a future non-meeting seam is a red pre-push gate, not a shipped-broken main. The blobs are never decoded, never synthesized, and never rendered into a packet — the packet renderer reads no foreign attrs keys, so the model never pays tokens for ciphertext it cannot read. Readable text keeps riding `assistant.reasoning`; the two never mix.
1336
1341
 
1337
- **The arrival law.** {§arrival-law} Every body lands as an entry and appears in the packet as a weighted meta line; how much body rides OPEN on arrival is set by INVITATION. **Self-invited** content — what this worker addressed by its own op (READ/FIND/OPEN results, its own exec streams) — rides open within free headroom; over, it arrives folded (the grinder + budget_overflow contract). **Pushed** content — text another actor put in front of this worker (the user prompt, a child's deliverable, a sibling irc) — rides the PREVIEW: whole when under the bound, the head + the cut statement + the pull address when over. The bound is `PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES` (default 16) lines AND 80×N chars — the char cap guards single-line bombs. The trust line is authorship: a worker's own ask is its curation, weighed in advance; another actor's push is unratified by the recipient at any size (run111: a child's legally-terminal 19,363-token deliverable landed whole in its parent, was relayed into a 40k child prompt, and cascaded the pipeline — #499). A child whose loop ends non-2xx already lands FOLDED (the termination-delta insert); the preview bounds the ratified-giant case. New lanes inherit the law at the arrival boundary — a future scheme or module cannot reopen the hole by adding a feature. The preview is enforced at RENDER for every pushed lane — the prompt foist's line-slice bounds lines, and the render's char cap cuts what a line-slice cannot (a single-line char-bomb prompt renders as its 80×N-char head + the cut statement + its address).
1342
+ **The arrival law.** {§arrival-law} Every body lands as an entry and appears in the packet as a weighted meta line; how much body rides OPEN on arrival is set by INVITATION. **Self-invited** content — what this worker addressed by its own op (READ/FIND/OPEN results, its own exec streams) — rides open within free headroom; over, it arrives folded (the grinder + budget_overflow contract). **Pushed** content — text another actor put in front of this worker (the user prompt, a child's deliverable, a sibling irc) — rides the PREVIEW: whole when under the bound, the head + the cut statement + the pull address when over. The bound is `PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES` (default 16) lines AND 80×N chars — the char cap guards single-line bombs. The trust line is authorship: a worker's own ask is its curation, weighed in advance; another actor's push is unratified by the recipient at any size (run111: a child's legally-terminal 19,363-token deliverable landed whole in its parent, was relayed into a 40k child prompt, and cascaded the pipeline — #499). A child whose loop ends non-2xx already lands FOLDED (the termination-delta insert); the preview bounds the ratified-giant case. New lanes inherit the law at the arrival boundary — a future scheme or module cannot reopen the hole by adding a feature. The preview is enforced at RENDER for every pushed lane — the prompt foist's line-slice bounds lines, and the render's char cap cuts what a line-slice cannot (a single-line char-bomb prompt renders as its 80×N-char head + the cut statement + its address). **A model's own COMPOSED op bodies ride the same preview** (#566): a `PLAN`/`SEND`/`WORK`/`FORK`'s text or an `EXEC` command renders preview-bounded (the same 16-line, 80×N-char bound), so no text the model composes can land as an unbounded OPEN log row. **CONTENT ops are exempt and render full** — `READ`/`FIND` (retrieved bytes; capping a `READ` would break its `<start,end>` slice contract) and `EDIT`/`COPY`/`MOVE` spans (the resulting file content the model inspects to confirm its edit). The line is compose-vs-inspect: a plan/message/task is composed text the model restates and never needs to re-read; a file span is bytes it reads back. `EDIT` is grinder-foldable (only `error`+`PLAN` are grinder-exempt), so even a large span reclaims — it was never the permanent-bomb shape. run42 is why: an unclosed `<<PLAN` swallowed a 57,276-char runaway emission into ONE 29k open `PLAN` row the grinder is forbidden to fold (§grinder-layer1-rollback exempts `PLAN` so the model always sees its plan), which pushed the packet past the provider's physical window and gated out the hard-413 recovery — a permanent, un-reclaimable budget bomb. The verbatim emission survives in the folded `model` mirror, so the render bound loses nothing. {§arrival-law-authored-bodies}
1338
1343
 
1339
- **Prompt as a first-class entry.** Each loop's prompt is written on loop start as a plurnk-origin `EDIT` against `prompt:///<loop>/<N>` (indexable, body channel, text/markdown); injected mid-loop prompts land the same way at their turn's slot. The **User Prompts** section closes the status clump (user slot, just above the recap — {§packet-cache-monotone}) as a PATHS-ONLY list (the errors shape — `* prompt:///<loop>/<N>`, no bodies): every prompt the loop holds stays listed and READable by address, so prior prompts are never silently lost and recovering them is never a curation imposition. {§prompt-auto-read} **The frame is SELF-ONLY and owner-keyed** (#527, closing #382 with zero exceptions): the entry's owner_id is the worker, the address carries only the loop coordinate — no worker identity ever rides a pathname or a packet. Concurrent workers' identical coordinates (every worker's first loop is sequence 1) are DISTINCT rows on the owner column, so a WORK-spawned sister's turn-1 foist can never clobber the parent's task. The scheme takes no authority slot: packets are per-worker and every cross-worker prompt flow (parent→child inject, the drain's orphan promotion) is engine-mediated, so a worker only ever addresses its own frames; every writer and query builds through one boundary (`plurnk-uri.promptPathname`/`promptLoopPrefix` + the query's owner param). The model never constructs the address — it READs what the section lists. {§prompt-self-only} **A loop CONTAINS its prompts — plural, ordinal-keyed** (owner ruling): a loop is created by its originating prompt (frame 1) and holds EVERY prompt that arrives before it concludes — each lands at the loop's next ordinal (`prompt:///<loop>/<N>`, the Nth prompt of the loop), so rapid arrivals are frames N and N+1, both kept, nothing superseded, and the key structurally cannot collide regardless of turn timing. A new prompt raises a NEW loop only when no active loop exists to contain it. Delivery is the next turn boundary's auto-READ of every not-yet-delivered frame (oldest first — the frame's own foisted READ in the loop is the delivery record); a frame still undelivered when the loop concludes is the orphan the drain promotes into a fresh loop, so no instruction is ever silently lost. {§prompt-loop-containment} The prompt's CONTENT reaches the model through a foisted auto-`READ` of its own entry — `<1,16>` (the §arrival-law preview bound, `PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES`), or `<1,-1>` when the prompt runs under it (the whole-read form doubles as teaching) — dispatched on the first turn for the loop prompt and on the landing turn for each injected prompt, so an arriving prompt always opens in the log like any retrieval. The foisted `EDIT`'s **log row is folded by default** (`expanded=0`): the body arrives via the auto-READ, so the log keeps the write for forensics while collapsing the duplicate, re-OPENable like any fold (§open-fold). {§prompt-fold} **A model `FOLD` targeting a prompt row is ILLEGAL** (#382 — a weak model in a housekeeping turn folded its own task auto-READ and lost the plot): the fold is refused (*"Illegal attempt to FOLD a user prompt. Use KILL if you want it removed."*), so the frame can't be accidentally hidden — while `KILL` still deletes it deliberately, preserving the model's curation of a prompt it genuinely wants gone. A glob sweep silently spares the prompt and folds the rest. {§prompt-fold-illegal}
1344
+ **Prompt as a first-class entry.** Each loop's prompt is written on loop start as a plurnk-origin `EDIT` against `prompt:///<loop>/<N>` (indexable, body channel, text/markdown); injected mid-loop prompts land the same way at their turn's slot. The **User Prompts** section closes the status clump (user slot, just above the recap — {§packet-cache-monotone}) as a PATHS-ONLY list (the errors shape — `* prompt:///<loop>/<N>`, no bodies): every prompt the loop holds stays listed and READable by address, so prior prompts are never silently lost and recovering them is never a curation imposition. {§prompt-auto-read} **The frame is SELF-ONLY and owner-keyed** (#527, closing #382 with zero exceptions): the entry's owner_id is the worker, the address carries only the loop coordinate — no worker identity ever rides a pathname or a packet. Concurrent workers' identical coordinates (every worker's first loop is sequence 1) are DISTINCT rows on the owner column, so a WORK-spawned sister's turn-1 foist can never clobber the parent's task. The scheme takes no authority slot: packets are per-worker and every cross-worker prompt flow (parent→child inject, the drain's orphan promotion) is engine-mediated, so a worker only ever addresses its own frames; every writer and query builds through one boundary (`plurnk-uri.promptPathname`/`promptLoopPrefix` + the query's owner param). The model never constructs the address — it READs what the section lists. {§prompt-self-only} **A loop CONTAINS its prompts — plural, ordinal-keyed** (owner ruling): a loop is created by its originating prompt (frame 1) and holds EVERY prompt that arrives before it concludes — each lands at the loop's next ordinal (`prompt:///<loop>/<N>`, the Nth prompt of the loop), so rapid arrivals are frames N and N+1, both kept, nothing superseded, and the key structurally cannot collide regardless of turn timing. A new prompt raises a NEW loop only when no active loop exists to contain it. Delivery is the next turn boundary's auto-READ of every not-yet-delivered frame (oldest first — the frame's own foisted READ in the loop is the delivery record); a frame still undelivered when the loop concludes is the orphan the drain promotes into a fresh loop, so no instruction is ever silently lost. {§prompt-loop-containment} The prompt's CONTENT reaches the model through a foisted auto-`READ` of its own entry — `<1,16>` (the §arrival-law preview bound, `PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES`), or `<1,-1>` when the prompt runs under it (the whole-read form doubles as teaching) — dispatched on the first turn for the loop prompt and on the landing turn for each injected prompt, so an arriving prompt always opens in the log like any retrieval. The foisted `EDIT`'s **log row is folded by default** (`expanded=0`): the body arrives via the auto-READ, so the log keeps the write for forensics while collapsing the duplicate, re-OPENable like any fold (§open-fold). {§prompt-fold} **A model `FOLD` targeting the CURRENT loop's foisted preview READ is ILLEGAL** (#382 — a weak model in a housekeeping turn folded its own task auto-READ and lost the plot): the fold is refused (*"Illegal attempt to FOLD the task preview. Use KILL if you want it removed."*), so the frame can't be accidentally hidden — while `KILL` still deletes it deliberately, preserving the model's curation of a prompt it genuinely wants gone. The refusal binds exactly one row (prompt target, origin plurnk, op `READ`, this loop): the born-folded `EDIT` foist, the model's own deeper prompt `READ`s, and prior loops' previews are ordinary curatable rows — a fold there is legal curation, and an OPENed frame body can always be folded back. A glob sweep silently spares the preview and folds the rest. {§prompt-fold-illegal}
1340
1345
 
1341
1346
  **The entry catalog.** The catalog is the **complete, unranked directory** of what a workspace 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}
1342
1347
 
@@ -1423,7 +1428,7 @@ Body matchers and `<L>` both dispatch on entry mimetype. Body matcher: leading-c
1423
1428
 
1424
1429
  ### §matcher-dispatch Matcher dispatch (service-owned, over daughter primitives)
1425
1430
 
1426
- `Matcher.matchAgainstContent` (in-tree, `src/content/matcher.ts`) is the **service's own** dialect dispatch — `Mimetypes.query` is NOT consumed (§mimetype-methods). It handles the **content dialects** and switches on each, calling the daughter's individual primitives: `glob → queryGlob` and `regex → queryRegex` over the raw content; `jsonpath → queryJsonpathObject` over the `deepJson` projection and `xpath → queryXpathString` over `deepXml` (both pulled from `mimetypes.process({channels})`, so a structural dialect works over any source type), returning `QueryMatch[]` rendered as `<source-line>:\t<line>`. `~semantic` and `@graph` are **relation dialects, not content matchers** — FIND resolves them upstream to `(file, span)` items (`~`semantic via `rankSemantic`, `@`graph via `EntryGraph`), so they never reach `matchAgainstContent` (a fail-hard invariant guards the impossible routing). Status mapping (content dialects):
1431
+ `Matcher.matchAgainstContent` (in-tree, `src/content/matcher.ts`) is the **service's own** dialect dispatch — `Mimetypes.query` is NOT consumed (§mimetype-methods). It handles the **content dialects** and switches on each, calling the daughter's individual primitives: `glob → queryGlob` and `regex → queryRegex` over the raw content; `jsonpath → queryJsonpathObject` over the `deepJson` projection and `xpath → queryXpathString` over `deepXml` (both pulled from `mimetypes.process({channels})`, so a structural dialect works over any source type), returning `QueryMatch[]` rendered as `<source-line>:<line>`. `~semantic` and `@graph` are **relation dialects, not content matchers** — FIND resolves them upstream to `(file, span)` items (`~`semantic via `rankSemantic`, `@`graph via `EntryGraph`), so they never reach `matchAgainstContent` (a fail-hard invariant guards the impossible routing). Status mapping (content dialects):
1427
1432
 
1428
1433
  | Result | HTTP status |
1429
1434
  |---|---|
@@ -1438,9 +1443,9 @@ Glob anchoring (`TODO*` starts-with, `*TODO*` contains, `*.log` ends-with, `[Tt]
1438
1443
 
1439
1444
  ### §matcher-result Matcher result shape — READ returns matching LINES, uniformly
1440
1445
 
1441
- The contract is the grammar's: **plurnk.md §"`<Line> / <Result>`" — "FIND returns rows of results, READ returns lines of content"**, and READ "prefixes every line with line numbers and a hard tab, `N:\t`" (one source-line number, not part of the source). This section documents the service's implementation of that.
1446
+ The contract is the grammar's: **plurnk.md §"`<Line> / <Result>`" — "FIND returns rows of results, READ returns lines of content"**, and READ "prefixes every line with its line number, `N:` — no separator whitespace" (#564 owner policy: a bare `N:` prefix; the old hard-tab separator leaked into edit bodies and corrupted indentation). The number is one source-line coordinate, not part of the source. This section documents the service's implementation of that.
1442
1447
 
1443
- **A matcher selects locations; it never extracts a value.** Every dialect identifies *where* in the source it matches; READ returns the **source line(s)** at those locations, faithfully — one shape for every dialect: `<line>:\t<line-content>`, prefixed with the single source-line number per plurnk.md (shifted back to source coordinates inside an `<L>` slice), never double-numbered. Empty → 204; mimetype `text/markdown` regardless of source. The model reads the line and adapts whatever it needs out of it — READ never pre-chews a match down to a bare value. {§matcher-result-read-returns-lines}
1448
+ **A matcher selects locations; it never extracts a value.** Every dialect identifies *where* in the source it matches; READ returns the **source line(s)** at those locations, faithfully — one shape for every dialect: `<line>:<line-content>`, prefixed with the single source-line number per plurnk.md (shifted back to source coordinates inside an `<L>` slice), never double-numbered. Empty → 204; mimetype `text/markdown` regardless of source. The model reads the line and adapts whatever it needs out of it — READ never pre-chews a match down to a bare value. {§matcher-result-read-returns-lines}
1444
1449
 
1445
1450
  | Dialect | Selects | Natural use |
1446
1451
  |---|---|---|
@@ -1523,14 +1528,14 @@ Same rule applies across Known, Unknown, Skill, Plurnk, File. Effective mimetype
1523
1528
 
1524
1529
  `packet-wire` log render branches on `isLineNavigableMimetype`:
1525
1530
 
1526
- - **Line-navigable** (text/markdown, text/plain, csv, source code, yaml, toml) → `N:\t` line-number prefix per line {§render-rule-line-navigable-prefix}
1527
- - **Tree-navigable** (application/json, application/xml, text/html, +json/+xml suffixes) → verbatim body (no `N:\t` — outer line numbers would collide with structural navigation like jsonpath/xpath) {§render-rule-tree-navigable-verbatim}
1531
+ - **Line-navigable** (text/markdown, text/plain, csv, source code, yaml, toml) → `N:` line-number prefix per line {§render-rule-line-navigable-prefix}
1532
+ - **Tree-navigable** (application/json, application/xml, text/html, +json/+xml suffixes) → verbatim body (no `N:` — outer line numbers would collide with structural navigation like jsonpath/xpath) {§render-rule-tree-navigable-verbatim}
1528
1533
 
1529
1534
  A log row renders its **result body** for the content-returning ops — `READ@200` (the content it pulled) and `FIND@200` (the catalog rows / matched entries it returned) — under the query's fence, mimetype-driven per the rules above; every other op re-emits its statement. FIND included: the model must see what a find *returned*, not just its echoed query, and the turn-0 foisted `FIND(scheme:///**)` reaches the packet through this branch — without it the catalog preview is invisible. {§render-rule-find-renders-result}
1530
1535
 
1531
1536
  An `EDIT` log row renders its **resulting span** — the edited area as it looks now (`rx.span`), under the target's fence — not the input statement: the log reads "and here's X now," so the model sees its edit's effect. The object still carries op + target; the model's own EDITs and the system delta-EDITs (§env-delta) render identically; an emptied span → the object's meta alone (no body). With no span stored, the row falls back to re-emitting the statement (the heredoc the model wrote). {§edit-result-render}
1532
1537
 
1533
- The `N:\t` prefix is presentation/reference per plurnk.md ("not part of the source"); stripped before any matcher operation on the log entry.
1538
+ The `N:` prefix is presentation/reference per plurnk.md ("not part of the source"); stripped before any matcher operation on the log entry.
1534
1539
 
1535
1540
  ### §markdown-primitive Mimetype primitive: text/markdown
1536
1541
 
@@ -1549,8 +1554,8 @@ Carried from the contract walk; durable.
1549
1554
  - **Dialect/mimetype mismatch** → 415 (xpath on text/plain → 415; jsonpath on JSON-shapeless mimetypes → 204 because outline is empty, not 415).
1550
1555
  - **Binary entries** → 415 across the board for READ/EDIT/OPEN/FOLD.
1551
1556
  - **EDIT `<L>` on non-existent entry** → body becomes content; `<L>` is positional-only on existing content.
1552
- - **COPY/MOVE `<L>`** → slices the SOURCE range into the destination (every channel), symmetric with READ `<L>` but WITHOUT the `N:\t` prefix (`sliceLinesRaw`); an out-of-range marker → 416. MOVE `<L>` copies the slice, then deletes the whole source (relocation of a fragment). Binary channels can't be sliced (the binary→415 rule above). {§copy-l-source-range}
1553
- - **READ rx** prefixes each line with `N:\t` per §render-rule. `sliceLinesRaw` (used by COPY) returns the lines without prefix.
1557
+ - **COPY/MOVE `<L>`** → slices the SOURCE range into the destination (every channel), symmetric with READ `<L>` but WITHOUT the `N:` prefix (`sliceLinesRaw`); an out-of-range marker → 416. MOVE `<L>` copies the slice, then deletes the whole source (relocation of a fragment). Binary channels can't be sliced (the binary→415 rule above). {§copy-l-source-range}
1558
+ - **READ rx** prefixes each line with `N:` per §render-rule. `sliceLinesRaw` (used by COPY) returns the lines without prefix.
1554
1559
  - **FIND body matcher** applies to entry content (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` (§matcher-dispatch; status 200 = content hit → entry selected). Scope + tags select candidates in SQL; the path-glob is the (target).
1555
1560
  - **OPEN/FOLD** operate on the **log** (`log:///`), not entries (§open-fold) — FOLD collapses a log row to its path, OPEN restores its body. Aimed at an entry scheme they return 501.
1556
1561
  - **SEND[410]** deletes as a side-effect (not the model idiom; §move): with `#fragment`, that channel only; without, the whole entry. **SEND[499]** is owned by the streaming scheme that holds the subscription.
@@ -28,6 +28,6 @@ export const editedSpan = (original, updated, context = 2) => {
28
28
  } // no added hunk (defensive) → whole
29
29
  const start = Math.max(0, lo - context);
30
30
  const end = Math.min(rows.length - 1, hi + context);
31
- return rows.slice(start, end + 1).map((r, i) => `${start + i + 1}:\t${r.text}`).join("\n");
31
+ return rows.slice(start, end + 1).map((r, i) => `${start + i + 1}:${r.text}`).join("\n");
32
32
  };
33
33
  //# sourceMappingURL=edited-span.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"edited-span.js","sourceRoot":"","sources":["../../src/content/edited-span.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,yFAAyF;AACzF,gFAAgF;AAChF,2EAA2E;AAC3E,2EAA2E;AAC3E,qFAAqF;AACrF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,OAAe,EAAE,OAAO,GAAG,CAAC,EAAU,EAAE;IACjF,MAAM,IAAI,GAAyC,EAAE,CAAC;IACtD,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;QAC9C,IAAI,IAAI,CAAC,OAAO;YAAE,SAAS,CAAE,0CAA0C;QACvE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;YAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAE,iCAAiC;QAC3F,KAAK,MAAM,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YAAC,IAAI,EAAE,GAAG,CAAC;gBAAE,EAAE,GAAG,CAAC,CAAC;YAAC,EAAE,GAAG,CAAC,CAAC;QAAC,CAAC;IAC1F,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QAAC,EAAE,GAAG,CAAC,CAAC;QAAC,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAAC,CAAC,CAAE,oCAAoC;IACnF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/F,CAAC,CAAC"}
1
+ {"version":3,"file":"edited-span.js","sourceRoot":"","sources":["../../src/content/edited-span.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,yFAAyF;AACzF,gFAAgF;AAChF,2EAA2E;AAC3E,2EAA2E;AAC3E,qFAAqF;AACrF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,OAAe,EAAE,OAAO,GAAG,CAAC,EAAU,EAAE;IACjF,MAAM,IAAI,GAAyC,EAAE,CAAC;IACtD,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;QAC9C,IAAI,IAAI,CAAC,OAAO;YAAE,SAAS,CAAE,0CAA0C;QACvE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;YAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAE,iCAAiC;QAC3F,KAAK,MAAM,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YAAC,IAAI,EAAE,GAAG,CAAC;gBAAE,EAAE,GAAG,CAAC,CAAC;YAAC,EAAE,GAAG,CAAC,CAAC;QAAC,CAAC;IAC1F,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QAAC,EAAE,GAAG,CAAC,CAAC;QAAC,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAAC,CAAC,CAAE,oCAAoC;IACnF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7F,CAAC,CAAC"}
@@ -17,7 +17,7 @@ export default class Matcher {
17
17
  // READ returns LINES of content (plurnk.md:31): a matcher SELECTS, READ delivers the
18
18
  // source line(s) at each match — not the extracted value. `m.lines` is each hit's source
19
19
  // span(s), uniform across dialects (the daughter self-provides them). One source-line
20
- // prefix `N:\t` (plurnk.md:32), deduped by source line; baseLine shifts slice-relative
20
+ // prefix `N:` (plurnk.md:32), deduped by source line; baseLine shifts slice-relative
21
21
  // spans back to source coordinates. A hit with no span (e.g. an xpath computed scalar —
22
22
  // count()/sum(), which has no source node) falls back to the matched value.
23
23
  static #renderRows(matches, content, baseLine) {
@@ -48,7 +48,7 @@ export default class Matcher {
48
48
  if (seen.has(src))
49
49
  continue;
50
50
  seen.add(src);
51
- rows.push(`${src}:\t${lines[ln - 1] ?? Matcher.#renderValue(m.matched)}`);
51
+ rows.push(`${src}:${lines[ln - 1] ?? Matcher.#renderValue(m.matched)}`);
52
52
  }
53
53
  }
54
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../src/content/matcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../src/content/matcher.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@
4
4
  // `MimetypeBinary.isBinaryMimetype(...)`.
5
5
  //
6
6
  // isBinaryMimetype — enforces 415 on binary entries (SPEC §op-invariants)
7
- // isLineNavigableMimetype — decides the render layer's `N:\t` line prefixes
7
+ // isLineNavigableMimetype — decides the render layer's `N:` line prefixes
8
8
  // TEXT_PRIMITIVE_MIMETYPE — text/markdown, the auto-derived text default
9
9
  import { MimetypeClassifier, TEXT_PRIMITIVE_MIMETYPE as _TEXT_PRIMITIVE_MIMETYPE } from "@plurnk/plurnk-schemes";
10
10
  export default class MimetypeBinary {
@@ -1 +1 @@
1
- {"version":3,"file":"mimetype-binary.js","sourceRoot":"","sources":["../../src/content/mimetype-binary.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,sEAAsE;AACtE,uEAAuE;AACvE,0CAA0C;AAC1C,EAAE;AACF,kFAAkF;AAClF,8EAA8E;AAC9E,2EAA2E;AAC3E,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,IAAI,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEjH,MAAM,CAAC,OAAO,OAAO,cAAc;IAC/B,MAAM,CAAC,uBAAuB,GAAG,wBAAwB,CAAC;IAC1D,MAAM,CAAC,gBAAgB,CAAC,QAAgB,IAAa,OAAO,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpG,MAAM,CAAC,cAAc,CAAC,QAAgB,IAAa,OAAO,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAChG,MAAM,CAAC,uBAAuB,CAAC,QAAgB,IAAa,OAAO,kBAAkB,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClH,MAAM,CAAC,yBAAyB,CAAC,QAAmC,IAAY,OAAO,kBAAkB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,wFAAwF;CACpO"}
1
+ {"version":3,"file":"mimetype-binary.js","sourceRoot":"","sources":["../../src/content/mimetype-binary.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,sEAAsE;AACtE,uEAAuE;AACvE,0CAA0C;AAC1C,EAAE;AACF,kFAAkF;AAClF,4EAA4E;AAC5E,2EAA2E;AAC3E,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,IAAI,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEjH,MAAM,CAAC,OAAO,OAAO,cAAc;IAC/B,MAAM,CAAC,uBAAuB,GAAG,wBAAwB,CAAC;IAC1D,MAAM,CAAC,gBAAgB,CAAC,QAAgB,IAAa,OAAO,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpG,MAAM,CAAC,cAAc,CAAC,QAAgB,IAAa,OAAO,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAChG,MAAM,CAAC,uBAAuB,CAAC,QAAgB,IAAa,OAAO,kBAAkB,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClH,MAAM,CAAC,yBAAyB,CAAC,QAAmC,IAAY,OAAO,kBAAkB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,wFAAwF;CACpO"}
@@ -1 +1 @@
1
- {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAwE,MAAM,wBAAwB,CAAC;AAMpI,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAiB,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;AAQ9C,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAI3I,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAc1C,OAAsB,EAAE,KAAK,WAAW,EAAwB,MAAM,oBAAoB,CAAC;AAE3F,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEvF,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIvE,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AA8CzG,OAAO,KAAK,EAAE,QAAQ,EAAmC,MAAM,0BAA0B,CAAC;AAuC1F,MAAM,CAAC,OAAO,OAAO,MAAM;;IACvB,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,MAAM,CAElE;IAED,MAAM,CAAC,WAAW,CACd,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,EAC9B,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACvB;QAAE,QAAQ,EAAE,KAAK,CAAA;KAAE,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAE1E;IAiBD,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAIxD,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAW9C,QAAQ,CAAC,UAAU,aAAoB;IA8BjC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEtC;IAkBD,YAAY,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,QAAQ,EAAE,EAAE;QACrI,EAAE,EAAE,EAAE,CAAC;QACP,OAAO,EAAE,cAAc,CAAC;QACxB,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;QACtC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;QACpC,YAAY,CAAC,EAAE,kBAAkB,CAAC;QAClC,YAAY,CAAC,EAAE,kBAAkB,CAAC;QAClC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;QAC5C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;KACvC,EAoCA;IAID,YAAY,CAAC,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAE9C;IAQD,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAOtD;IA+DK,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5D;IAED,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAEjD;IAEK,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAehM;IAiBK,OAAO,CAAC,EACV,QAAQ,EAAE,QAAQ,EAAE,YAAiB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EACpE,QAAa,EAAE,UAA6B,EAC5C,SAA4E,EAC5E,cAA6F,EAC7F,MAAgB,EAAE,MAAM,EAAE,UAAU,GACvC,EAAE;QACC,QAAQ,EAAE,QAAQ,CAAC;QACnB,QAAQ,EAAE,WAAW,EAAE,CAAC;QAIxB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,UAAU,CAAC;QACpB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;KAC7C,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,WAAW,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,cAAc,GAAG,UAAU,GAAG,IAAI,CAAA;KAAE,CAAC,CA0J/K;IAEK,OAAO,CAAC,EACV,QAAQ,EAAE,QAAQ,EAAE,YAAiB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAgB,EAAE,MAAM,EAAE,UAAU,EAC1G,UAAc,EAAE,QAAa,GAChC,EAAE;QACC,QAAQ,EAAE,QAAQ,CAAC;QACnB,QAAQ,EAAE,WAAW,EAAE,CAAC;QACxB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QACtD,MAAM,CAAC,EAAE,UAAU,CAAC;QACpB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;QAK1C,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC,CA4sB7J;IAmED,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAEjF;IAiJK,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAEhE;IAIK,IAAI,CAAC,OAAO,EAAE;QAChB,SAAS,EAAE,eAAe,CAAC;QAC3B,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QACtD,MAAM,CAAC,EAAE,UAAU,CAAC;KACvB,GAAG,OAAO,CAAC,cAAc,CAAC,CAE1B;IAMD,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAExC;IAED,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAExE;IAGD,kBAAkB,IAAI,MAAM,EAAE,CAE7B;IAKD,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,IAAI,CAEvE;IAMK,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG/D;IASK,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAajE;IAcK,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CACnD;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAC7C,CA4BA;CAaJ"}
1
+ {"version":3,"file":"Engine.d.ts","sourceRoot":"","sources":["../../src/core/Engine.ts"],"names":[],"mappings":"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"}
@@ -358,6 +358,12 @@ export default class Engine {
358
358
  wall.unref();
359
359
  const timedOut = () => loopAbort.signal.aborted && loopAbort.signal.reason === LOOP_TIMEOUT_REASON;
360
360
  const ruleTimeout = async () => {
361
+ // {§loop-terminals} — EVERY abandonment names itself (#555; the full terminal
362
+ // enumeration, not the two first found): live fan-out before cleanup wipes the buffer.
363
+ this.#telemetry.push(workspaceId, loopId, {
364
+ source: "engine:rails", kind: "loop_timeout", level: "error",
365
+ message: `loop abandoned 504: the loop wall expired after ${turnIds.length} turns`,
366
+ });
361
367
  await this.#db.engine_loop_set_status.run({ loop_id: loopId, status: 504, message: "loop_timeout" });
362
368
  cleanup("forceful", "loop_timeout");
363
369
  return { turnIds, finalStatus: 504, hitMaxTurns: false, reason: "loop_timeout" };
@@ -408,6 +414,12 @@ export default class Engine {
408
414
  if (maxTurns >= 0 && turnIds.length >= maxTurns) {
409
415
  // §loop-terminals — the turn ceiling is exhausted: 429 Too Many Requests
410
416
  // (kin to the soft sudden-death 429 warnings that precede it).
417
+ // {§loop-terminals} — even the EXPECTED ceiling names itself (warn, not error:
418
+ // the client configured maxTurns; hitting it is a bound, not a malfunction).
419
+ this.#telemetry.push(workspaceId, loopId, {
420
+ source: "engine:rails", kind: "max_turns", level: "warn",
421
+ message: `loop ended 429: the configured turn ceiling (${maxTurns}) is exhausted`,
422
+ });
411
423
  await this.#db.engine_loop_set_status.run({ loop_id: loopId, status: 429, message: "max_turns" });
412
424
  cleanup("forceful", "max_turns");
413
425
  return { turnIds, finalStatus: 429, hitMaxTurns: true, reason: "max_turns" };
@@ -456,6 +468,11 @@ export default class Engine {
456
468
  // SPEC §grinder: budget hard-stop — packet won't fit even collapsed → abandon.
457
469
  if (turn.budgetHardStop) {
458
470
  // §loop-terminals — the packet won't fit even collapsed: 413 Content Too Large.
471
+ // Same silent-terminal class as strike_threshold ({§loop-terminals}, #555): name it.
472
+ this.#telemetry.push(workspaceId, loopId, {
473
+ source: "engine:rails", kind: "budget_overflow", level: "error",
474
+ message: `loop abandoned 413: the packet exceeds the budget even after the newest turn folded — unrecoverable overflow after ${turnIds.length} turns`,
475
+ });
459
476
  await this.#db.engine_loop_set_status.run({ loop_id: loopId, status: 413, message: "budget_overflow" });
460
477
  cleanup("forceful", "budget_overflow");
461
478
  return { turnIds, finalStatus: 413, hitMaxTurns: false, reason: "budget_overflow" };
@@ -476,6 +493,16 @@ export default class Engine {
476
493
  // (508 Loop Detected); a failure/no-op strike is the model failing (500
477
494
  // Internal Server Error). The straw that crossed the threshold picks it.
478
495
  const status = verdict.cycleDetected ? 508 : 500;
496
+ // {§loop-terminals} — the abandonment NAMES ITSELF (#506 promise; run60/#555): a
497
+ // deliberate strike terminal returns a clean finalStatus, so the drain's loop_error
498
+ // catch never sees it and the death would be silent on every channel. Emit a legible
499
+ // error event — live fan-out fires here, BEFORE cleanup deletes the loop's buffer.
500
+ this.#telemetry.push(workspaceId, loopId, {
501
+ source: "engine:rails", kind: "strike_threshold", level: "error",
502
+ message: verdict.cycleDetected
503
+ ? `loop abandoned ${status}: strike threshold crossed after ${turnIds.length} turns — the model was spinning in place (cycle detected)`
504
+ : `loop abandoned ${status}: strike threshold crossed after ${turnIds.length} turns — repeated failed or no-op turns`,
505
+ });
479
506
  await this.#db.engine_loop_set_status.run({ loop_id: loopId, status, message: "strike_threshold" });
480
507
  cleanup("forceful", "strike_threshold");
481
508
  return { turnIds, finalStatus: status, hitMaxTurns: false, reason: "strike_threshold" };
@@ -1016,9 +1043,24 @@ export default class Engine {
1016
1043
  // Provisional here — a terminal REFUSED at dispatch (the pending-set 409, only knowable
1017
1044
  // post-dispatch) demotes the turn back to a continue below: the SEND's signal stays on the
1018
1045
  // row (the un-erased record), but the loop never went terminal, so the turn didn't either.
1019
- let turnStatus = sendOp !== undefined
1020
- ? sendOp.signal
1021
- : realOpsCount === 0 ? TURN_STATUS_NO_OPS : TURN_STATUS_IMPLICIT_CONTINUE;
1046
+ // §broken-packet-no-dispatch (#566) a BROKEN PACKET is structurally incomplete: the
1047
+ // provider GUILLOTINED the emission at the completion cap (finish=length) and it failed the
1048
+ // parse (empty, or cut mid-op). Its parsed "ops" are a severed frame — garbage (run42: an
1049
+ // unclosed `<<PLAN` swallowed a 57k-char runaway into one bogus status-200 PLAN). Nothing
1050
+ // dispatches and the turn is a NO-OPS strike, so a repeated runaway can't spin as a 102
1051
+ // "continue". The turn still records — the folded `model` mirror + the output_truncated 413 +
1052
+ // the parse-error rows — so the model sees WHY next turn and re-emits through the existing
1053
+ // error channel (no same-turn re-generate). A "flubbed op" is DIFFERENT: a well-framed turn
1054
+ // (finish=stop) whose single op erred dispatches its valid ops and steers on the bad one (the
1055
+ // recovery rail); only a severed FRAME is refused wholesale. The formal framing-vs-op-local
1056
+ // error split is grammar's to tag.
1057
+ const brokenPacket = callMetadata.finishReason === "length"
1058
+ && (packetAssistant.content.trim().length === 0 || (parseErrors?.length ?? 0) > 0);
1059
+ let turnStatus = brokenPacket
1060
+ ? TURN_STATUS_NO_OPS
1061
+ : sendOp !== undefined
1062
+ ? sendOp.signal
1063
+ : realOpsCount === 0 ? TURN_STATUS_NO_OPS : TURN_STATUS_IMPLICIT_CONTINUE;
1022
1064
  // Idle turn: an implicit-continue (102) that did no WORK — its ops are only PLAN/SEND, no mid op.
1023
1065
  // The model continued with nothing to do. (Skipped when premature already steered this turn.)
1024
1066
  // #467 (owner criterion) — a turn whose op ATTEMPTS died at the parser is a FAILED-RETRIEVAL
@@ -1078,11 +1120,15 @@ export default class Engine {
1078
1120
  // actions — they always dispatch and never count against the cap. maxCommands
1079
1121
  // bounds real actions only; maxCommands:0 still admits a plan and a conclusion
1080
1122
  // (the PLAN/SEND ops, zero actions), which is its only coherent meaning.
1123
+ // §broken-packet-no-dispatch (#566) — the severed frame dispatches NOTHING (rationale +
1124
+ // status handling at the brokenPacket definition above).
1081
1125
  let realCommands = 0;
1082
- const opsToDispatch = packetAssistant.ops.filter((op) => op.op === "PLAN"
1126
+ const opsToDispatch = brokenPacket ? [] : packetAssistant.ops.filter((op) => op.op === "PLAN"
1083
1127
  || (op.op === "SEND" && typeof op.signal === "number" && op.signal >= 200)
1084
1128
  || realCommands++ < maxCommands);
1085
- const droppedCount = opsCount - opsToDispatch.length;
1129
+ // A broken packet's ops aren't max_commands drops — they're refused wholesale, and the
1130
+ // output_truncated 413 already tells the model why; don't also mint max_commands_exceeded.
1131
+ const droppedCount = brokenPacket ? 0 : opsCount - opsToDispatch.length;
1086
1132
  const statuses = [];
1087
1133
  // Running counter — a multi-file READ writes N rows from one statement (rowsWritten),
1088
1134
  // so the next op's sequence picks up after them. Collapses to nextActionIndex+i when