@plurnk/plurnk-contracts 4.1.0 → 6.0.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/SPEC.md +378 -268
- package/dist/conformance/agui-v1.json +24 -15
- package/dist/schema/EntryReadResult.json +3 -2
- package/dist/schema/McpOAuth.json +24 -3
- package/dist/src/AguiConformance.js.map +1 -1
- package/dist/src/Application.d.ts +71 -0
- package/dist/src/Application.d.ts.map +1 -1
- package/dist/src/ApplicationPort.d.ts +44 -7
- package/dist/src/ApplicationPort.d.ts.map +1 -1
- package/dist/src/ApplicationStream.d.ts +24 -0
- package/dist/src/ApplicationStream.d.ts.map +1 -0
- package/dist/src/ApplicationStream.js +2 -0
- package/dist/src/ApplicationStream.js.map +1 -0
- package/dist/src/CapabilityAdmission.js.map +1 -1
- package/dist/src/Excerpt.d.ts +5 -0
- package/dist/src/Excerpt.d.ts.map +1 -0
- package/dist/src/Excerpt.js +15 -0
- package/dist/src/Excerpt.js.map +1 -0
- package/dist/src/Functionality.d.ts +14 -13
- package/dist/src/Functionality.d.ts.map +1 -1
- package/dist/src/LoopLifecycle.d.ts +1 -1
- package/dist/src/LoopLifecycle.d.ts.map +1 -1
- package/dist/src/LoopLifecycle.js +5 -5
- package/dist/src/LoopLifecycle.js.map +1 -1
- package/dist/src/MessageResource.d.ts +12 -0
- package/dist/src/MessageResource.d.ts.map +1 -1
- package/dist/src/Problems.d.ts.map +1 -1
- package/dist/src/Problems.js +2 -1
- package/dist/src/Problems.js.map +1 -1
- package/dist/src/Validator.d.ts +26 -22
- package/dist/src/Validator.d.ts.map +1 -1
- package/dist/src/Validator.js +111 -63
- package/dist/src/Validator.js.map +1 -1
- package/dist/src/guards.d.ts +4 -0
- package/dist/src/guards.d.ts.map +1 -0
- package/dist/src/guards.js +8 -0
- package/dist/src/guards.js.map +1 -0
- package/dist/src/index.d.ts +6 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/types.d.ts +1 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.generated.d.ts +26 -1
- package/dist/src/types.generated.d.ts.map +1 -1
- package/dist/src/types.js +11 -3
- package/dist/src/types.js.map +1 -1
- package/package.json +4 -4
- package/plurnk.md +21 -20
package/SPEC.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## 1. Overview
|
|
4
4
|
|
|
5
|
+
<!-- map -->
|
|
6
|
+
| Tag | Promise |
|
|
7
|
+
| --- | --- |
|
|
8
|
+
| {§contract-representations} | JSON Schema is authoritative for shared data shapes. |
|
|
9
|
+
| {§agui-discovery-contract} | `AguiDiscovery` is the complete installed AG-UI+ surface at one instant. |
|
|
10
|
+
| {§agui-action-schema-enforcement} | The JSON Schema values in {§agui-discovery-contract} are executable boundary contracts, not prose or hints. |
|
|
11
|
+
| {§agui-client-conformance} | `AguiClientConformance` is a language-neutral JSON document accounting for every action and notification in… |
|
|
12
|
+
| {§agui-conformance-kit} | `AguiConformanceKit` is the one versioned, language-neutral corpus of raw SSE boundary specimens and AG-UI… |
|
|
13
|
+
| {§json-result-rendering} | `renderJsonResult` renders compact aggregate operation rows. |
|
|
14
|
+
| {§json-document-presentation} | Generated JSON documents use two-space indentation. |
|
|
15
|
+
<!-- /map -->
|
|
16
|
+
|
|
5
17
|
This package is the single authority for PLURNK's language, schemas, generated types and
|
|
6
18
|
runtime-neutral wire envelopes; `@plurnk/plurnk-parser` implements the language it specifies
|
|
7
19
|
({§parser-consumers}). Its package root is the single code API for those contracts
|
|
@@ -92,6 +104,24 @@ metadata retain their deliberate layouts.
|
|
|
92
104
|
|
|
93
105
|
## 1.1 Contract layers and admission boundary
|
|
94
106
|
|
|
107
|
+
<!-- map -->
|
|
108
|
+
| Tag | Promise |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| {§contract-proposal-projection} | Admission policy and stopped-world projection |
|
|
111
|
+
| {§capability-policy-matching} | A selector is an exact conjunction: every field it declares must equal the descriptor, while every selected… |
|
|
112
|
+
| {§capability-policy-cascade} | Capability layers are purely subtractive and order-independent: a descriptor is admitted only when every… |
|
|
113
|
+
| {§capability-policy-projection} | A `CapabilityProjection` reports every durable workspace layer and their normalized intersection: `service`,… |
|
|
114
|
+
| {§proposal-policy} | `ProposalPolicy` names one server disposition; `PROPOSAL_POLICIES` is its schema-owned vocabulary. |
|
|
115
|
+
| {§effort-wire} | `Effort` is exactly `off \| adaptive \| low \| medium \| high \| xhigh \| max`. |
|
|
116
|
+
| {§model-catalog-wire} | `ModelRoute` is one exact client-visible provider/model identity with optional alias provenance. |
|
|
117
|
+
| {§client-interaction-wire} | Client-owned interaction wire |
|
|
118
|
+
| {§provider-usage} | `ProviderUsage` records only known non-negative safe-integer quantities. |
|
|
119
|
+
| {§provider-cost} | `ProviderCost` represents one physical provider request's monetary disposition. |
|
|
120
|
+
| {§provider-request-accounting} | `ProviderRequestAccounting` is the indivisible accounting fact for one issued physical request. |
|
|
121
|
+
| {§provider-request-evidence} | The physical-request settlement may also carry JSON-serializable, provider-owned response/failure evidence. |
|
|
122
|
+
| {§provider-accounting} | `ProviderAccounting.requests` is the source evidence. |
|
|
123
|
+
<!-- /map -->
|
|
124
|
+
|
|
95
125
|
One contract, deliberately different projections (ARCHITECTURE.md). Each layer
|
|
96
126
|
below owns what it alone can decide.
|
|
97
127
|
|
|
@@ -262,6 +292,55 @@ and parse diagnostics are separate contracts.
|
|
|
262
292
|
|
|
263
293
|
## §canonical-statement 2. Canonical statement form
|
|
264
294
|
|
|
295
|
+
<!-- map -->
|
|
296
|
+
| Tag | Promise |
|
|
297
|
+
| --- | --- |
|
|
298
|
+
| {§section-boundary} | Every statement is one backtick block. |
|
|
299
|
+
| {§fence-closer} | A block opened with N backticks closes at a line made of at least N backticks and nothing else but horizontal… |
|
|
300
|
+
| {§balanced-fences} | A complete nested interpretation takes precedence over missing-closer recovery. |
|
|
301
|
+
| {§operation-fences} | Accept three or more backticks; teach and render three. |
|
|
302
|
+
| {§naked-operation} | A native name with only an optional aside opens without a fence. |
|
|
303
|
+
| {§fence-heading-in-body} | Outside a complete nested block ({§balanced-fences}), a fence line of three or more backticks carrying a… |
|
|
304
|
+
| {§closer-fallback} | A block that ends at a heading or at the end of the input has no closer of its own; its body is the whole… |
|
|
305
|
+
| {§fence-boundary} | Every fence line inside a body takes one of these meanings, chosen for the whole input at once by… |
|
|
306
|
+
| {§fence-pairing} | Fence pairing |
|
|
307
|
+
| {§pairing-need} | Why a pass ahead of the grammar. |
|
|
308
|
+
| {§pairing-algorithm} | Algorithm. |
|
|
309
|
+
| {§pairing-objective} | Objective. |
|
|
310
|
+
| {§unclosed-mutation-yields} | A mutation body never swallows a native operation. |
|
|
311
|
+
| {§prose-code-blocks} | A message or a prompt shows code. |
|
|
312
|
+
| {§message-run-on} | A message runs to the end of the turn. |
|
|
313
|
+
| {§pairing-witness} | Witnesses. |
|
|
314
|
+
| {§indented-fences} | CommonMark's indentation, everywhere. |
|
|
315
|
+
| {§inline-chain} | A closer on a heading line, or on a body's closing line, may be followed on that same line by the next… |
|
|
316
|
+
| {§transparent-inline-closer} | A closer mid-heading is read as if it were not written. |
|
|
317
|
+
| {§executor-case} | An executor tag in any case. |
|
|
318
|
+
| {§executor-js-spelling} | When `node` is registered and `js` is not, `js` names `node` under {§executor-case}. |
|
|
319
|
+
| {§one-line-turn} | A whole turn on one line. |
|
|
320
|
+
| {§anchor-digits} | In a text scope, `@` followed by one to four digits cannot be a hash and is read as that line number, with… |
|
|
321
|
+
| {§unclosed-aside} | A heading whose aside opens with `<!--` and never closes on its line takes the rest of the line as the aside,… |
|
|
322
|
+
| {§quotation} | A fence that opens no operation quotes. |
|
|
323
|
+
| {§forgotten-tag} | A tag on the line under a bare fence is the operation. |
|
|
324
|
+
| {§executor-heading} | Syntax identifies an invocation; dispatch resolves its runtime. |
|
|
325
|
+
| {§interstitial-fence} | Only a heading under {§executor-heading} opens an operation. |
|
|
326
|
+
| {§closer-aside} | A closing fence followed on its line by one aside and nothing else is the closer; the aside is outside text. |
|
|
327
|
+
| {§heading-slot-order} | A heading near-miss with exactly one reading is read as that reading, with no diagnostic and no teaching… |
|
|
328
|
+
| {§native-tool-calls} | An emission that yields no operation may be a model's native tool-call markup naming a plurnk operation or a… |
|
|
329
|
+
| {§native-tool-call-receipt} | Unexecuted native markup draws a warning. |
|
|
330
|
+
| {§empty-section} | Both the compact bodyless form and an empty multiline block normalize optional bodies to null. |
|
|
331
|
+
| {§statement-rendering} | `PlurnkParser.stringify` renders native OP names and named runtime fences from the shared AST, with one blank… |
|
|
332
|
+
| {§slot-order} | Producers put target, scope, metadata, then aside, separated by one ASCII space. |
|
|
333
|
+
| {§lifecycle-slots} | NOTE accepts no target, scope, or metadata. |
|
|
334
|
+
| {§target-group} | READ and KILL take a target group. |
|
|
335
|
+
| {§safe-uri-target-groups} | An explicit URI list is a target group. |
|
|
336
|
+
| {§scope-on-scopeless} | A scope on an operation that takes none is dropped, and named. |
|
|
337
|
+
| {§heading-inline-body} | Nonempty body text belongs below the fence header. |
|
|
338
|
+
| {§bare-option-object} | A bare option object is the option block, where the house option array owns the block. |
|
|
339
|
+
| {§operation-aside} | The final header modifier may be one single-line HTML comment. |
|
|
340
|
+
| {§scheme-metadata-modifier} | A target may carry one single-line `[metadata]` block, placed under {§slot-order}; executor and SEND fences… |
|
|
341
|
+
| {§matcher-option} | `pattern` is the matcher, and it lives in the heading. |
|
|
342
|
+
<!-- /map -->
|
|
343
|
+
|
|
265
344
|
`````text
|
|
266
345
|
```OP (path)? <scope>? [metadata]? <!-- aside -->?
|
|
267
346
|
body
|
|
@@ -291,7 +370,7 @@ rule.
|
|
|
291
370
|
|
|
292
371
|
§balanced-fences A complete nested interpretation takes precedence over missing-closer
|
|
293
372
|
recovery. Within a body, a line-leading labeled fence opens a literal block, and an equal or
|
|
294
|
-
wider bare fence nests
|
|
373
|
+
wider bare fence nests unless closing there costs the reading less
|
|
295
374
|
({§fence-pairing}). A nested block ends at its first valid closer, as a CommonMark code block
|
|
296
375
|
does. So a wider outer fence holds any narrower body, finished or not, and equal widths nest
|
|
297
376
|
when every inner block closes. Preserve every nested body byte, including apparent operations
|
|
@@ -309,23 +388,13 @@ fence only as the nesting form. Every producer of a statement — the parser, a
|
|
|
309
388
|
`/look`, a client's tab-completion — writes `PLURNK_FENCE` rather than its own literal
|
|
310
389
|
(plurnk/plurnk#92).
|
|
311
390
|
|
|
312
|
-
§naked-operation **A native name with only an optional aside opens without a fence.** A
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
back ({§closer-fallback}). One warning-severity receipt follows a recovered statement —
|
|
320
|
-
`` `NOTE` opened with no fence; the taught form is three backticks. `` One rule for every native
|
|
321
|
-
operation: a naked `WAIT` parks, a naked `NOTE` takes its text, a naked `READ` meets the ordinary
|
|
322
|
-
missing-target refusal. A closer the author wrote anyway is still not body: when the body's last line is
|
|
323
|
-
a bare backtick fence that no other fence line in the body pairs with (an odd count of fence lines), that
|
|
324
|
-
line is the block's closer and leaves the body, so `SEND`, then the answer, then a closing fence delivers
|
|
325
|
-
the answer alone. An aside-bearing name inside a body is not a closer. An incomplete or repeated
|
|
326
|
-
aside, an operand, or other heading text does not qualify and remains the unfenced form
|
|
327
|
-
({§unfenced-operation}). Executors are runtimes rather than operations, and reasoning is never
|
|
328
|
-
read this way.
|
|
391
|
+
§naked-operation **A native name with only an optional aside opens without a fence.** A column-zero line outside any block containing a native operation's name and at most one complete `<!-- aside -->`, with only horizontal whitespace otherwise, opens that operation as if it were fenced with the taught three backticks. The aside retains its ordinary meaning: no target or modifiers are inferred. One warning-severity receipt follows a recovered statement — `` `NOTE` opened with no fence; the taught form is three backticks. `` One rule for every native operation: a naked `WAIT` parks, a naked `NOTE` takes its text, a naked `READ` meets the ordinary missing-target refusal. Executors are runtimes rather than operations, and reasoning is never read this way.
|
|
392
|
+
|
|
393
|
+
| Fact | Rule |
|
|
394
|
+
| --- | --- |
|
|
395
|
+
| The body | runs to a line that is exactly the name again, to the next heading ({§fence-heading-in-body}), or to the end of the turn; a fence inside naming nothing known is body; the block expects no closer, so its body is never cut back ({§closer-fallback}) |
|
|
396
|
+
| A closer the author wrote anyway | still not body: when the body's last line is a bare backtick fence that no other fence line in the body pairs with (an odd count of fence lines), that line is the block's closer and leaves the body, so `SEND`, then the answer, then a closing fence delivers the answer alone; an aside-bearing name inside a body is not a closer |
|
|
397
|
+
| Not the form | an incomplete or repeated aside, an operand, or other heading text does not qualify and remains the unfenced form ({§unfenced-operation}) |
|
|
329
398
|
|
|
330
399
|
§fence-heading-in-body Outside a complete nested block ({§balanced-fences}), a fence
|
|
331
400
|
line of three or more backticks carrying a heading under {§executor-heading}
|
|
@@ -389,54 +458,41 @@ alternative (§4.2), so neither mode chooses among complete readings by cost. Th
|
|
|
389
458
|
Python (`INDENT`/`DEDENT`) and PHP (heredoc) grammars settle block structure the same way:
|
|
390
459
|
outside the grammar, then hand the lexer tokens.
|
|
391
460
|
|
|
392
|
-
§pairing-algorithm **Algorithm.** Each line is classified by the lexer's line-start rules: text, a
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
every place the block could end to its cheapest reading up to there
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
strictly less, so each entry is the reading a preference-ordered exhaustive search returns.
|
|
401
|
-
Inside a quotation or a nested block the first valid closer closes, CommonMark's rule, applied
|
|
402
|
-
as a disambiguation filter (Klint and Visser, 1994); an operation body keeps the choice between
|
|
403
|
-
nesting and closing. A block opened by a bare fence must hold a line, except a quotation at the
|
|
404
|
-
top level: two stray fences in a row there are an empty quotation, shown and harmless, rather
|
|
405
|
-
than two repairs that a reading could avoid only by hiding an operation.
|
|
461
|
+
§pairing-algorithm **Algorithm.** Each line is classified by the lexer's line-start rules: text, a bare fence, a labeled fence, a heading, a closer glued to a heading, or a naked operation name. Evaluation runs on an explicit work stack.
|
|
462
|
+
|
|
463
|
+
| Step | Rule |
|
|
464
|
+
| --- | --- |
|
|
465
|
+
| Summaries | a block's contents read the same whatever lies beneath it on the stack, so the pass summarizes each (position, block, what the block holds so far) once; for a nested block, the summary maps every place the block could end to its cheapest reading up to there, and parents compose their children's summaries; an outermost block is evaluated in the root's frame, where only the cost to the end of the input matters, so it holds one entry |
|
|
466
|
+
| Candidates | taken in preference order and replace one another only by costing strictly less, so each entry is the reading a preference-ordered exhaustive search returns |
|
|
467
|
+
| Closers | inside a quotation or a nested block the first valid closer closes, CommonMark's rule, applied as a disambiguation filter (Klint and Visser, 1994); an operation body keeps the choice between nesting and closing |
|
|
468
|
+
| A block opened by a bare fence | must hold a line, except a quotation at the top level: two stray fences in a row there are an empty quotation, shown and harmless, rather than two repairs that a reading could avoid only by hiding an operation |
|
|
406
469
|
|
|
407
470
|
§pairing-objective **Objective.** A complete reading, one that needs no repair, wins over every
|
|
408
471
|
repaired reading: a complete nested interpretation takes precedence. Each class has its own order.
|
|
409
472
|
|
|
410
473
|
| Counted | Complete readings | Repaired readings | Why |
|
|
411
474
|
|---|---|---|---|
|
|
412
|
-
| Hidden operations: a heading that will not run, written at its block's width or wider | 1, together with
|
|
475
|
+
| Hidden operations: a heading that will not run, written at its block's width or wider | 1, together with discarded code | 1 | Every operation the author wrote should run |
|
|
413
476
|
| Repairs: a supplied closer (except a message's run to the end of the input, {§message-run-on}), a fence read as a stray, a narrower closer accepted, a body under an operation that takes none (COPY, MOVE, non-log targeted KILL), a body not well-formed in the media type its runtime declares ({§executor-invocation}) | none by definition | 2 | The least-errors distance |
|
|
414
|
-
| Literal by declaration: a heading narrower than its block, or no wider than the labeled block or example holding it, or inside a quotation or a KILL, or an executor heading inside a SEND, WORK, FORK or BARE body ({§prose-code-blocks})
|
|
477
|
+
| Literal by declaration: a heading narrower than its block, or no wider than the labeled block or example holding it, or inside a quotation or a KILL, or an executor heading shown as a code block inside a SEND, WORK, FORK or BARE body ({§prose-code-blocks}) | none: the author's enclosure wrote it as an example | 3, together with the row below | A heading the author wrapped is the example it was written as |
|
|
478
|
+
| Discarded code: a labeled fence in a body read as text, or such an executor heading read as text | 1, together with hidden operations | 3, together with the row above | Every code block the author declared should stand |
|
|
415
479
|
| Supplied closers | 2 | 4 | A block the author opened should end at a fence the author wrote |
|
|
416
480
|
| Other fences read as text | 3 | 5 | The least departure from the fences as written |
|
|
417
481
|
|
|
418
|
-
Complete readings compare
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
a repaired total may take either class for any of its parts
|
|
425
|
-
|
|
426
|
-
§unclosed-mutation-yields **A mutation body never swallows a native operation.** An example
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
So where ```` ```EDIT (b.py) ```` follows ```` ```EDIT (a.py) ```` with no closer between, the
|
|
433
|
-
reading that supplies `a.py`'s closer before that heading wins, both EDITs run, and no operation
|
|
434
|
-
heading is written into a file; the same shape with a closer after the example is fence-identical
|
|
435
|
-
and reads the same way. Of 67 recorded EDIT bodies holding a native heading, 66 use the wider fence
|
|
436
|
-
and read unchanged, and the one at equal width (glm run158) had written a test EDIT's heading and
|
|
437
|
-
body into `functional.py` and never run it. Only EDIT mutates from its body, so only EDIT carries
|
|
438
|
-
the rule: an executor heading inside an EDIT keeps the ordinary reading, and SEND, WORK, FORK and
|
|
439
|
-
BARE bodies keep {§prose-code-blocks}.
|
|
482
|
+
Complete readings compare as a single least-errors order over departures from the fences as written, and a heading the author enclosed in a wider or labeled fence is the example it was written as, not a departure.
|
|
483
|
+
|
|
484
|
+
| Rule | What |
|
|
485
|
+
| --- | --- |
|
|
486
|
+
| A narrower message fence | a message whose own fence is narrower than the fences wrapping its examples still holds them: the reading that lets a wrapper close the message and runs the examples ties on cost and loses on preference, since a body nests before it closes ({§balanced-fences}) |
|
|
487
|
+
| A broken shape | once every reading of an emission needs a repair, its shape is already broken, and saving a repair is not worth an operation the author wrote |
|
|
488
|
+
| The summary | keeps, for every place a block could end, the best complete reading under each order and the best repaired reading, so the search stays exact: a repaired total may take either class for any of its parts |
|
|
489
|
+
|
|
490
|
+
§unclosed-mutation-yields **A mutation body never swallows a native operation.** An example inside an EDIT is written with a wider outer fence ({§operation-fences}); a heading narrower than the EDIT's fence is literal by declaration and stays text. At the EDIT's own width a native operation heading runs, closed or not: read as the body's example it would be a *swallowed* operation, and a swallowed operation outranks any number of repairs — a reading that swallows one is never complete, and among repaired readings the fewest swallowed wins before every other class. Only EDIT mutates from its body, so only EDIT carries the rule: an executor heading inside an EDIT keeps the ordinary reading, and SEND, WORK, FORK and BARE bodies keep {§prose-code-blocks}.
|
|
491
|
+
|
|
492
|
+
| Shape | Reading |
|
|
493
|
+
| --- | --- |
|
|
494
|
+
| ```` ```EDIT (b.py) ```` follows ```` ```EDIT (a.py) ```` with no closer between | the reading that supplies `a.py`'s closer before that heading wins, both EDITs run, and no operation heading is written into a file |
|
|
495
|
+
| The same shape with a closer after the example | fence-identical, and reads the same way |
|
|
440
496
|
|
|
441
497
|
Equal cost goes to the earlier alternative: nesting before closing in an operation body,
|
|
442
498
|
closing before nesting in a quotation, and a supplied closer before a literal example at a
|
|
@@ -537,24 +593,14 @@ draws one warning that it was shown, not run. At the top level, a bare fence who
|
|
|
537
593
|
operation heading opens that operation instead ({§forgotten-tag}). A labeled block is an example by
|
|
538
594
|
declaration, and nothing else inside draws an advisory.
|
|
539
595
|
|
|
540
|
-
§forgotten-tag **A tag on the line under a bare fence is the operation.** At the top level, a bare
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
bare fence alone draws nothing; in the 10,486-emission fence corpus every one of the 12 that open
|
|
549
|
-
that way was an operation the model meant to run. An example the model means only to show
|
|
550
|
-
belongs in a properly nested body ({§balanced-fences}) or a quotation ({§quotation}).
|
|
551
|
-
So a model may show plurnk's own operations in an answer. Two exceptions keep programs whole:
|
|
552
|
-
CommonMark's own rule that a backtick opener's line carries no further backtick, so
|
|
553
|
-
```` ```READ (x)``` ```` is inline code and quotes nothing after it; and a bare fence directly under
|
|
554
|
-
a line carrying a fence run, which is an orphaned closer and quotes nothing. An unknown tag
|
|
555
|
-
without invocation slots is a code block and draws nothing. An offset example draws nothing either
|
|
556
|
-
({§indented-fences}). Quotation outside an operation is
|
|
557
|
-
response text under {§response-text}, not an executable program or a completion envelope.
|
|
596
|
+
§forgotten-tag **A tag on the line under a bare fence is the operation.** At the top level, a bare fence whose next line is an operation heading, a native name alone or with a slot or an executor's name with its operand, opens that operation as if both were written on one line: the heading takes its slots, the lines after it are its body, and it closes like any operation. It runs, and one warning-severity receipt names the form — `` `READ` ran, though its fence was malformed: the opening fence, OP, parameters, and aside share one line. `` Saying that it ran keeps the model from issuing it again. Inside a body the same lines stay literal. A bare fence alone draws nothing: nearly every one holds code or quoted output. An example the model means only to show belongs in a properly nested body ({§balanced-fences}) or a quotation ({§quotation}), so a model may show plurnk's own operations in an answer. Quotation outside an operation is response text under {§response-text}, not an executable program or a completion envelope.
|
|
597
|
+
|
|
598
|
+
| Draws nothing | Why |
|
|
599
|
+
| --- | --- |
|
|
600
|
+
| ```` ```READ (x)``` ```` on one line | CommonMark's own rule that a backtick opener's line carries no further backtick: it is inline code and quotes nothing after it |
|
|
601
|
+
| A bare fence directly under a line carrying a fence run | an orphaned closer; it quotes nothing |
|
|
602
|
+
| An unknown tag without invocation slots | a code block |
|
|
603
|
+
| An offset example | {§indented-fences} |
|
|
558
604
|
|
|
559
605
|
`plurnk.md` names the tab offset as the form for an example, in the aside of its nesting
|
|
560
606
|
example, and shows its own examples offset; the other quoting fences are untaught: a tilde
|
|
@@ -592,43 +638,27 @@ reading, with no diagnostic and no teaching (#758):
|
|
|
592
638
|
|
|
593
639
|
Tokens keep their source positions; only their order in the stream changes.
|
|
594
640
|
|
|
595
|
-
§native-tool-calls An emission that yields no operation may be a model's native
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
followed by `<arg_key>`/`<arg_value>` pairs (GLM)
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
`
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
its
|
|
615
|
-
|
|
616
|
-
spelled without spaces. An executor's unknown parameter is one of its options, `[{"maxTokens":
|
|
617
|
-
"2500"}]`, for its owner to accept or refuse; `bash` names `sh` when `sh` is the registered shell.
|
|
618
|
-
Calls that cannot be mapped draw {§native-tool-call-receipt}.
|
|
619
|
-
Qwen's own shapes read the same way: a flat JSON call whose operation is the value
|
|
620
|
-
of an `op`, `action` or `cmd` key in any case (`{"op": "READ", "path": …, "range": …}`),
|
|
621
|
-
an XML element named by the operation (`<NOTE>…</NOTE>`, `<FIND (path) <1,3></FIND>`,
|
|
622
|
-
`<read path="…"/>`) or by a generic `op` element or function (`<op op="READ" …>`,
|
|
623
|
-
`<op verb="READ" …/>` in `<ops>`, `<op=READ (path) …>`, `<function=OP name="READ" …>`,
|
|
624
|
-
`<function=OP>` around such a JSON call or a plurnk heading), and a plurnk heading written
|
|
625
|
-
as the call's text (`<tool_call>READ (a.py) <60,120>`, `=READ (…)`). Closing tags left over
|
|
626
|
-
from another family (`</parameter>`, `</invoke>`, `</>`) after a call are markup noise;
|
|
627
|
-
`reason` and `description` are the aside; a scope may be a JSON array (`[500,530]`) or a
|
|
628
|
-
`{"start", "end"}` object; an executor's string `input` is its program. A call with an
|
|
629
|
-
unknown name or parameter, or a FIND, READ, EDIT, COPY or MOVE naming no target, leaves the
|
|
630
|
-
whole emission as it was. An emission that already yields an operation is never
|
|
631
|
-
rewritten. No diagnostic, notice or teaching mentions a successful reading (#760).
|
|
641
|
+
§native-tool-calls **An emission that yields no operation may be a model's native tool-call markup naming a plurnk operation or a known executor, and every popular family is read the same way.** A block keeps its line count where its lines allow, so statement positions name the source line; an inline block grows to its fences. A call with an unknown name or parameter, or a FIND, READ, EDIT, COPY or MOVE naming no target, leaves the whole emission as it was; calls that cannot be mapped draw {§native-tool-call-receipt}. An emission that already yields an operation is never rewritten. No diagnostic, notice or teaching mentions a successful reading (#760).
|
|
642
|
+
|
|
643
|
+
| Family | Shape |
|
|
644
|
+
| --- | --- |
|
|
645
|
+
| DeepSeek | `<||DSML|| calls>` blocks of `invoke` elements with `parameter` children; DeepSeek writes the whole heading into the invoke's name — `<||DSML|| invoke name="FIND (docs/**) /Http404/ <!-- docs mentions -->">`, or `name="sh` with no closing quote and the script on the lines below — and the element's content is the body: the first word of the name is the operation, the rest its slots, and `parameter` tags around the content are debris, as are a copied facts line (`{"lines":6}`) under the heading, a `comment` attribute (the aside), and `<||DSML||tool_calls>` spelled without spaces |
|
|
646
|
+
| Anthropic-style | `<function_calls>` blocks of `invoke` elements with `parameter` children |
|
|
647
|
+
| The `<tool_call>` family | `<function=NAME>` with `<parameter=key>` children (Qwen, MiMo); a JSON object with `name` and `arguments` (Hermes and kin); a name followed by `<arg_key>`/`<arg_value>` pairs (GLM) |
|
|
648
|
+
| Llama | a bare `<function=NAME>` element; a `<\|python_tag\|>` JSON object |
|
|
649
|
+
| Mistral | a `[TOOL_CALLS]` JSON array |
|
|
650
|
+
| Kimi | `<\|tool_call_begin\|>` sections |
|
|
651
|
+
| Qwen's own shapes | a flat JSON call whose operation is the value of an `op`, `action` or `cmd` key in any case (`{"op": "READ", "path": …, "range": …}`); an XML element named by the operation (`<NOTE>…</NOTE>`, `<FIND (path) <1,3></FIND>`, `<read path="…"/>`) or by a generic `op` element or function (`<op op="READ" …>`, `<op verb="READ" …/>` in `<ops>`, `<op=READ (path) …>`, `<function=OP name="READ" …>`, `<function=OP>` around such a JSON call or a plurnk heading); a plurnk heading written as the call's text (`<tool_call>READ (a.py) <60,120>`, `=READ (…)`) |
|
|
652
|
+
|
|
653
|
+
| Call piece | Read as |
|
|
654
|
+
| --- | --- |
|
|
655
|
+
| `path`/`target`/`file_path`/`file`/`resource`/`uri` | the target |
|
|
656
|
+
| `scope`/`range`/`lines`, `start`/`end` written apart, `offset`/`limit` (a first line and a count), a JSON array (`[500,530]`) or a `{"start", "end"}` object | the scope; plurnk slots written after the name are kept, and a trailing scope's own bracket may close the tag |
|
|
657
|
+
| `pattern`/`regex`/`query` | a matcher option |
|
|
658
|
+
| `aside`, `reason`, `description` | the aside |
|
|
659
|
+
| `body`/`content`/`command`/`text`/`input` or plain text inside the call; an executor's string `input` | the body, an executor's program |
|
|
660
|
+
| An executor's unknown parameter | one of its options, `[{"maxTokens": "2500"}]`, for its owner to accept or refuse; `bash` names `sh` when `sh` is the registered shell |
|
|
661
|
+
| Closing tags left over from another family (`</parameter>`, `</invoke>`, `</>`) after a call | markup noise |
|
|
632
662
|
|
|
633
663
|
Bare `invoke` elements use the same slots as wrapped calls. A complete JSON object
|
|
634
664
|
inside an invoke supplies arguments when no explicit parameter elements are
|
|
@@ -683,18 +713,14 @@ is refused; the recovery is the scope's working form ({§parse-recovery}).
|
|
|
683
713
|
optional target and duration under {§send-wait-scope}. Their literal bodies begin
|
|
684
714
|
below the header.
|
|
685
715
|
|
|
686
|
-
§target-group **READ and KILL take a target group.** A READ or KILL heading may carry several
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
member, in authored order, each with its own target, scope, metadata and resolved matcher
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
once, with the first member. COPY and MOVE keep their two operands with their own meaning
|
|
695
|
-
({§transfer-resource-selections}); every other operation takes one slot, and a second slot on its
|
|
696
|
-
heading is the slot-opener diagnostic. The form is accepted, not taught: it rescues a bulk attempt
|
|
697
|
-
written one path per slot.
|
|
716
|
+
§target-group **READ and KILL take a target group.** A READ or KILL heading may carry several `(path)` slots, each binding the scope and metadata that follow it under {§slot-order}; a naked pattern on the heading ({§naked-pattern}) supplies the default for each member without its own metadata `pattern`. The form is accepted, not taught: it rescues a bulk attempt written one path per slot.
|
|
717
|
+
|
|
718
|
+
| Fact | Rule |
|
|
719
|
+
| --- | --- |
|
|
720
|
+
| Compilation | the parser compiles the complete heading into one ordinary statement per member, in authored order, each with its own target, scope, metadata and resolved matcher; no duplicated first-member or group representation crosses the parser boundary |
|
|
721
|
+
| Position and aside | every resulting statement retains the heading's source position and aside; a heading-level parse error refuses all its members, not valid sibling headings |
|
|
722
|
+
| A distilling body ({§log-kill-distillation}) | lands once, with the first member |
|
|
723
|
+
| Other operations | COPY and MOVE keep their two operands with their own meaning ({§transfer-resource-selections}); every other operation takes one slot, and a second slot on its heading is the slot-opener diagnostic |
|
|
698
724
|
|
|
699
725
|
§safe-uri-target-groups **An explicit URI list is a target group.** In READ and KILL only,
|
|
700
726
|
one path slot may contain several explicit `scheme://` URIs separated by top-level commas or
|
|
@@ -731,18 +757,13 @@ compact empty block or permit unmatched fences.
|
|
|
731
757
|
| executors | The input body, including an unbracketed JSON object; metadata requires brackets. |
|
|
732
758
|
| NOTE, WAIT, KILL without a target | The body. |
|
|
733
759
|
|
|
734
|
-
§bare-option-object A bare option object is the option block, where the house option array owns the
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
warning-severity receipt names the indulgence in place of the {§heading-inline-body} advisory:
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
type; their metadata is only the bracketed slot ({§scheme-metadata-modifier}). A heading that already carries a block keeps the object as
|
|
742
|
-
inline body. On FIND, READ and KILL the same text is the matcher
|
|
743
|
-
({§naked-pattern}), because a search for JSON text is legitimate; a bare matcher
|
|
744
|
-
that parses as a JSON object draws one advisory saying so: "`{…}` was read as the
|
|
745
|
-
matcher." ({§diagnostic-observation}).
|
|
760
|
+
§bare-option-object **A bare option object is the option block, where the house option array owns the block.** Executor headings always read an unbracketed object as input under {§heading-inline-body}, regardless of registration or input media type; their metadata is only the bracketed slot ({§scheme-metadata-modifier}).
|
|
761
|
+
|
|
762
|
+
| Heading | `{…}` after the slots is |
|
|
763
|
+
| --- | --- |
|
|
764
|
+
| SEND, BARE, WORK and FORK, where the heading admits a block (BARE, WORK and FORK only after their target) | read as `[{…}]`: the AST carries the array form, the written heading renders it, and one warning-severity receipt names the indulgence in place of the {§heading-inline-body} advisory: "`SEND` took a bare option object; the taught form is `[{…}]`." |
|
|
765
|
+
| One that already carries a block | inline body |
|
|
766
|
+
| FIND, READ and KILL | the matcher ({§naked-pattern}), because a search for JSON text is legitimate; a bare matcher that parses as a JSON object draws one advisory saying so: "`{…}` was read as the matcher." ({§diagnostic-observation}) |
|
|
746
767
|
|
|
747
768
|
§operation-aside The final header modifier may be one single-line HTML
|
|
748
769
|
comment. AstBuilder removes its delimiters and surrounding whitespace into
|
|
@@ -774,25 +795,14 @@ Two keys never reach an owner:
|
|
|
774
795
|
service's environment option on the operations that open a process or a
|
|
775
796
|
Worker; the shared reader withholds both from the owner's options.
|
|
776
797
|
|
|
777
|
-
§matcher-option **`pattern` is the matcher, and it lives in the heading.** On
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
positioned
|
|
783
|
-
|
|
784
|
-
the
|
|
785
|
-
language lifts only from one block that parses as a JSON array of objects;
|
|
786
|
-
anything else lifts nothing and reaches the owner's `400` untouched. A
|
|
787
|
-
`pattern` that is present but not a string is the language's own positioned
|
|
788
|
-
diagnostic, as is a matcher of a claimed dialect that fails admission. FIND and
|
|
789
|
-
READ bodies become memory under {§retrieval-annotation}; a non-log KILL's body is
|
|
790
|
-
unused and receives the advisory under {§matcher-body-redirect}. The heading line
|
|
791
|
-
is the matcher's home ({§naked-pattern}). EDIT keeps its literal body:
|
|
792
|
-
with a matcher it is the replacement for every selected span ({§edit-pattern}),
|
|
793
|
-
and an absent body deletes them. `PlurnkParser.stringify` writes a lifted matcher
|
|
794
|
-
whose block left no metadata back bare when the bare form reads back identically
|
|
795
|
-
and draws no advisory ({§naked-pattern}), otherwise as `[{"pattern": "…"}]`.
|
|
798
|
+
§matcher-option **`pattern` is the matcher, and it lives in the heading.** On FIND, READ, KILL, EDIT, and each COPY/MOVE operand, the option `[{"pattern": "<matcher>"}]` carries the matcher string: the leading prefix claims its dialect under {§matcher-prefix-claims}, and AstBuilder lifts it into the statement's `matcher` (`MatcherBody | null`), positioned dialect errors included. The heading line is the matcher's home ({§naked-pattern}).
|
|
799
|
+
|
|
800
|
+
| Fact | Rule |
|
|
801
|
+
| --- | --- |
|
|
802
|
+
| The block | one that carries only `pattern` leaves `metadata: null` for the owner; beside other keys the block stays with the owner verbatim, and the owner's reader treats `pattern` as reserved; the language lifts only from one block that parses as a JSON array of objects, and anything else lifts nothing and reaches the owner's `400` untouched |
|
|
803
|
+
| Diagnostics | a `pattern` that is present but not a string is the language's own positioned diagnostic, as is a matcher of a claimed dialect that fails admission |
|
|
804
|
+
| Bodies | FIND and READ bodies become memory under {§retrieval-annotation}; a non-log KILL's body is unused and receives the advisory under {§matcher-body-redirect}; EDIT keeps its literal body: with a matcher it is the replacement for every selected span ({§edit-pattern}), and an absent body deletes them |
|
|
805
|
+
| `PlurnkParser.stringify` | writes a lifted matcher whose block left no metadata back bare when the bare form reads back identically and draws no advisory ({§naked-pattern}), otherwise as `[{"pattern": "…"}]` |
|
|
796
806
|
|
|
797
807
|
## 3. Lexical elements
|
|
798
808
|
|
|
@@ -808,6 +818,30 @@ and draws no advisory ({§naked-pattern}), otherwise as `[{"pattern": "…"}]`.
|
|
|
808
818
|
|
|
809
819
|
## §op-shapes 4. Per-operation semantics
|
|
810
820
|
|
|
821
|
+
<!-- map -->
|
|
822
|
+
| Tag | Promise |
|
|
823
|
+
| --- | --- |
|
|
824
|
+
| {§retrieval-annotation} | A retrieval's authored body is memory, not selection or output. |
|
|
825
|
+
| {§note-value} | NOTE retains its literal body as ordinary model-owned working memory. |
|
|
826
|
+
| {§reasoning-operations} | The shared fence parser admits complete, line-leading NOTE, FIND and READ statements from exposed provider… |
|
|
827
|
+
| {§exec-executor-slot} | The fence name selects the executor directly: for example, `python3 (tools/report.py)` or `gitea… |
|
|
828
|
+
| {§turn-disposition} | WAIT requests parking; its literal body does not control scheduling, and its optional target is the label the… |
|
|
829
|
+
| {§send-wait-scope} | WAIT's optional `[seconds]` metadata is a non-negative finite scalar bounding this park, not the lifetime of… |
|
|
830
|
+
| {§send-directed-scope} | A recipient SEND carries an optional numeric scope after its target and metadata through to the addressed… |
|
|
831
|
+
| {§kill-scope} | KILL takes an optional text-coordinate scope beside its target, and an optional matcher. |
|
|
832
|
+
| {§bracket-metadata-slot} | Brackets are the owner's metadata modifier: the runtime or MCP service is the fence name, and tool input… |
|
|
833
|
+
| {§text-scope-semantics} | Exact regions use 1-based lines and Unicode code-point columns. |
|
|
834
|
+
| {§bare-statement} | BARE requests one isolated model inference. |
|
|
835
|
+
| {§read-find-normalization} | An authored READ is never rewritten into a FIND. |
|
|
836
|
+
| {§local-path-fragment} | A bare path takes `#channel` like a URL. |
|
|
837
|
+
| {§read-exact-target} | READ targets one exact resource (a local path or scheme URL, with optional `#channel` fragment or… |
|
|
838
|
+
| {§unscoped-edit-create-only} | No scope and an existing target is refused. |
|
|
839
|
+
| {§empty-mutation-scope} | Empty mutation content has one writable position: `<0>`, `<1>`, `<-1>`, and `<1,-1>` all insert the body as… |
|
|
840
|
+
| {§transfer-resource-selections} | COPY and MOVE require two singular `ResourceSelection` operands, source first and destination second, and… |
|
|
841
|
+
| {§find-result-unit} | For FIND, target selection fixes the paginated result unit after scheme address resolution… |
|
|
842
|
+
| {§copy-move-observation} | COPY and MOVE log projections preserve both admitted operand selections, including their independent scopes,… |
|
|
843
|
+
<!-- /map -->
|
|
844
|
+
|
|
811
845
|
The model-facing forms below are the canonical projection. Parser tolerance is
|
|
812
846
|
governed by {§canonical-statement}; runtime conditions remain explicit below.
|
|
813
847
|
|
|
@@ -840,9 +874,10 @@ is curated normally. Explicit NOTE remains the taught form.
|
|
|
840
874
|
§note-value NOTE retains its literal body as ordinary model-owned working memory.
|
|
841
875
|
It has no target, scope, metadata, or lifecycle effect. Its full body participates
|
|
842
876
|
in ordinary log token accounting and model-driven curation; prior notes are not
|
|
843
|
-
automatically hidden.
|
|
844
|
-
|
|
845
|
-
completion; ordinary repetition and strike rules
|
|
877
|
+
automatically hidden. A continuing or parked turn that carried no NOTE is told so in
|
|
878
|
+
the next packet ({§continued-without-note}); the omission is never a failure. A
|
|
879
|
+
NOTE-only turn does not request completion; ordinary repetition and strike rules
|
|
880
|
+
still apply.
|
|
846
881
|
|
|
847
882
|
§reasoning-operations The shared fence parser admits complete, line-leading NOTE,
|
|
848
883
|
FIND and READ statements from exposed provider reasoning. Admission is part of
|
|
@@ -902,20 +937,13 @@ semantics or refuses it; worker actors refuse one (`scope-unsupported`, 400). A
|
|
|
902
937
|
targetless message takes no scope. A scope never changes the message body or
|
|
903
938
|
disposition.
|
|
904
939
|
|
|
905
|
-
§kill-scope KILL takes an optional text-coordinate scope beside its target, numeric or
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
it is the model's distillation of what the KILL retires and lands as its own NOTE row
|
|
913
|
-
({§log-kill-distillation}); every other targeted KILL has `body: null`, and a body beneath one
|
|
914
|
-
draws the advisory ({§matcher-body-redirect}). Beneath a `log:///` KILL the body is never read as
|
|
915
|
-
a matcher; an inline pattern on the heading line still lifts.
|
|
916
|
-
Without a scope, KILL retires or deletes the whole target; with one, it removes exactly
|
|
917
|
-
that span — of a log body's packet projection or of an entry's content. Core owns the
|
|
918
|
-
one-way semantics: there is no operation that restores a scoped-away log body.
|
|
940
|
+
§kill-scope **KILL takes an optional text-coordinate scope beside its target, and an optional matcher.** The scope is numeric or anchored (```` ```KILL (log:///**/READ) <17,-1>``` ```` or ```` ```KILL (worker:///notes.md) <@aB3dE,@0Aa9Z>``` ````); the matcher option selects rows or lines (```` ```KILL (log:///**) [{"pattern": "~stale"}]``` ````, {§matcher-option}). Each operand becomes an ordinary KILL statement with its own `target`, `lineMarker` and `matcher`; no grouped AST reaches execution ({§target-group}). KILL requires a target.
|
|
941
|
+
|
|
942
|
+
| Fact | Rule |
|
|
943
|
+
| --- | --- |
|
|
944
|
+
| The body | retained on a `log:///` target, where it is the model's distillation of what the KILL retires and lands as its own NOTE row ({§log-kill-distillation}); every other targeted KILL has `body: null`, and a body beneath one draws the advisory ({§matcher-body-redirect}); beneath a `log:///` KILL the body is never read as a matcher, while an inline pattern on the heading line still lifts |
|
|
945
|
+
| Without a scope | KILL retires or deletes the whole target |
|
|
946
|
+
| With one | it removes exactly that span — of a log body's packet projection or of an entry's content; Core owns the one-way semantics: there is no operation that restores a scoped-away log body |
|
|
919
947
|
|
|
920
948
|
§bracket-metadata-slot Brackets are the owner's metadata modifier: the runtime
|
|
921
949
|
or MCP service is the fence name, and tool input belongs in the body. A bracket
|
|
@@ -933,22 +961,16 @@ KILL admits only its one- and two-line forms for canonical log-body visibility:
|
|
|
933
961
|
| two integers | Whole physical lines `firstLine..lastLine` | Both lines are included |
|
|
934
962
|
| four integers | Exact `startLine,startColumn,endLine,endColumn` region | Start included, end excluded; equality is zero-width |
|
|
935
963
|
|
|
936
|
-
§text-scope-semantics Exact regions use 1-based lines and Unicode code-point columns
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
so `<3,1,3,-1>` is line 3 to its end and `<3,-1,3,-1>` appends to that line. As an unadvertised
|
|
947
|
-
ingestion tolerance, the runtime accepts three integers as
|
|
948
|
-
`startLine,startColumn,endLine` and immediately normalizes them to the complete
|
|
949
|
-
four-coordinate region ending after the final code point of `endLine`.
|
|
950
|
-
Producers never emit that form. Other arities and decimal text coordinates are
|
|
951
|
-
runtime 416 failures.
|
|
964
|
+
§text-scope-semantics **Exact regions use 1-based lines and Unicode code-point columns.** One- and two-integer line selections normalize to the same exclusive-end `TextRegion` used by four-coordinate selections. Whole-line replacement deliberately accounts for newline separators; it is an ergonomic projection over exact replacement, not a different mimetype navigation mode. An end bound beyond the available content clamps to the final addressable endpoint; the start bound must resolve. Other arities and decimal text coordinates are runtime 416 failures.
|
|
965
|
+
|
|
966
|
+
| `-1` as | Means |
|
|
967
|
+
| --- | --- |
|
|
968
|
+
| A one-integer mutation scope | the append point |
|
|
969
|
+
| The end of an inclusive range | through the last line |
|
|
970
|
+
| An exact region's start or end line | the end of the content, so `<1,1,-1,1>` is the whole text and `<-1,1,-1,1>` appends |
|
|
971
|
+
| A column | the end of its line, so `<3,1,3,-1>` is line 3 to its end and `<3,-1,3,-1>` appends to that line |
|
|
972
|
+
|
|
973
|
+
An unadvertised ingestion tolerance: the runtime accepts three integers as `startLine,startColumn,endLine` and immediately normalizes them to the complete four-coordinate region ending after the final code point of `endLine`; producers never emit that form.
|
|
952
974
|
|
|
953
975
|
§bare-statement **BARE requests one isolated model inference.** Its optional
|
|
954
976
|
path names a prompt resource; its body supplies inline prompt text. At least
|
|
@@ -1042,6 +1064,15 @@ retrieval never returns inline within the emitting turn.
|
|
|
1042
1064
|
|
|
1043
1065
|
## §path-syntax 5. Target and path grammar
|
|
1044
1066
|
|
|
1067
|
+
<!-- map -->
|
|
1068
|
+
| Tag | Promise |
|
|
1069
|
+
| --- | --- |
|
|
1070
|
+
| {§path-query} | The serialized query component is the lossless representation. |
|
|
1071
|
+
| {§path-parentheses} | An unescaped depth-zero `)` closes the target slot. |
|
|
1072
|
+
| {§path-glob} | `PathSyntax` owns exact-path versus path-pattern classification. |
|
|
1073
|
+
| {§worker-name} | The exported `WORKER_NAME` contract governs names minted for URI authority slots:… |
|
|
1074
|
+
<!-- /map -->
|
|
1075
|
+
|
|
1045
1076
|
The target slot contains either a local path or a scheme URL. Exact addresses
|
|
1046
1077
|
and path globs share the slot; content matchers follow the heading forms in
|
|
1047
1078
|
{§matcher-option}.
|
|
@@ -1104,6 +1135,17 @@ ingestion restriction: the parser decomposes arbitrary URL authorities.
|
|
|
1104
1135
|
|
|
1105
1136
|
## §matcher-prefix-claims 6. Bulk pattern matching
|
|
1106
1137
|
|
|
1138
|
+
<!-- map -->
|
|
1139
|
+
| Tag | Promise |
|
|
1140
|
+
| --- | --- |
|
|
1141
|
+
| {§heading-boundary-recovery} | A column-0 heading is the trustworthy boundary. |
|
|
1142
|
+
| {§scope-slot-tolerance} | A line scope written inside a path slot (```` ```COPY (worker:///src.md<2,3>) ````) is read as… |
|
|
1143
|
+
| {§extra-path-slot} | A path slot beyond the operation's admitted operands — one for every operation, two for COPY and MOVE, any… |
|
|
1144
|
+
| {§matcher-refusal} | A matcher the parser cannot read refuses its operation, never the turn. |
|
|
1145
|
+
| {§regex-dialect-readings} | Three habits of other regex dialects are read, with one advisory each. |
|
|
1146
|
+
| {§pattern-body-single-line} | Every matcher is one physical line. |
|
|
1147
|
+
<!-- /map -->
|
|
1148
|
+
|
|
1107
1149
|
FIND, READ, KILL, EDIT, and the COPY/MOVE operands accept an optional matcher
|
|
1108
1150
|
through the `pattern` option ({§matcher-option}). AstBuilder assigns the dialect from the
|
|
1109
1151
|
matcher's leading characters. A leading prefix claims its dialect. Invalid
|
|
@@ -1177,6 +1219,14 @@ statements remain recoverable when their boundaries are trustworthy.
|
|
|
1177
1219
|
|
|
1178
1220
|
## §scope-slot 7. Scope markers
|
|
1179
1221
|
|
|
1222
|
+
<!-- map -->
|
|
1223
|
+
| Tag | Promise |
|
|
1224
|
+
| --- | --- |
|
|
1225
|
+
| {§text-line-anchor-syntax} | A text coordinate admits a case-sensitive line anchor spelled `@` followed by exactly five Base62 characters… |
|
|
1226
|
+
| {§scope-marker-forms} | Canonical producers separate components with commas and no spaces. |
|
|
1227
|
+
| {§scope-range-recovery} | For FIND result positions and text-coordinate operations, the parser normalizes these two-component numeric… |
|
|
1228
|
+
<!-- /map -->
|
|
1229
|
+
|
|
1180
1230
|
The model-facing slot is `<scope>`; the AST field is
|
|
1181
1231
|
`lineMarker`. Numeric scopes preserve ordered components in `LineMarker`;
|
|
1182
1232
|
text-coordinate operations use `TextLineMarker`, whose line positions may also
|
|
@@ -1269,6 +1319,16 @@ rule protects code examples in SEND, WORK, FORK, BARE and every other body.
|
|
|
1269
1319
|
|
|
1270
1320
|
## 9. Turn dispositions
|
|
1271
1321
|
|
|
1322
|
+
<!-- map -->
|
|
1323
|
+
| Tag | Promise |
|
|
1324
|
+
| --- | --- |
|
|
1325
|
+
| {§send-mid-reservation} | WAIT is reserved ({§turn-disposition}). |
|
|
1326
|
+
| {§disposition-anywhere} | A disposition may sit anywhere in a model turn without imposing a program boundary. |
|
|
1327
|
+
| {§park-202-only} | WAIT joins live work: an open stream or a live child. |
|
|
1328
|
+
| {§lifecycle-only-turn} | A WAIT-, SEND-, NOTE-, or KILL-only turn is valid. |
|
|
1329
|
+
| {§send-body} | SEND body projection |
|
|
1330
|
+
<!-- /map -->
|
|
1331
|
+
|
|
1272
1332
|
The runtime adjudicates each admitted turn against actual message resolutions,
|
|
1273
1333
|
results and live obligations ({§wait-obligation-matrix}). A response with no
|
|
1274
1334
|
operation resolves no message and creates no new observation obligation ({§empty-turn}).
|
|
@@ -1346,6 +1406,14 @@ stateDiagram-v2
|
|
|
1346
1406
|
|
|
1347
1407
|
## §whitespace-contract 11. Whitespace and interstatement text
|
|
1348
1408
|
|
|
1409
|
+
<!-- map -->
|
|
1410
|
+
| Tag | Promise |
|
|
1411
|
+
| --- | --- |
|
|
1412
|
+
| {§response-text} | The parser owns the partition between operations and response text. |
|
|
1413
|
+
| {§unfenced-operation} | The parser identifies ignored unfenced fragments. |
|
|
1414
|
+
| {§recorded-emissions} | The parser is regressed against emissions models actually produced, not fixtures we wrote. |
|
|
1415
|
+
<!-- /map -->
|
|
1416
|
+
|
|
1349
1417
|
Body framing removes the header line ending and the single line ending
|
|
1350
1418
|
immediately before the closing fence. Every other body character is preserved,
|
|
1351
1419
|
including leading/trailing blank lines, indentation, CRLF and literal
|
|
@@ -1379,23 +1447,26 @@ complete aside opens the operation instead ({§naked-operation}). A registered e
|
|
|
1379
1447
|
followed by an operand slot — `gitea (list_issues)`, `sh(build.sh)` — draws the same warning under
|
|
1380
1448
|
the executor's own spelling. Quoted blocks, offset lines and names inside a sentence draw nothing.
|
|
1381
1449
|
|
|
1382
|
-
§recorded-emissions **The parser is regressed against emissions models actually produced,
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
Shape coverage, not volume, is the point — 120 exemplars are ~60 KB against ~88 MB for
|
|
1390
|
-
every emission ever recorded. The recorded status is **provenance, never an assertion**:
|
|
1391
|
-
the contract has changed under these turns and will again, so the replay asserts only that
|
|
1392
|
-
today's parser still reads each emission the way the corpus says it does. Regenerate with
|
|
1393
|
-
`scriptify/extract-emission-corpus.ts --write` after a drill; a changed shape is the
|
|
1394
|
-
contract moving and the diff names every shape that moved with it. The extractor also
|
|
1395
|
-
reports how many recorded turns concluded in a way the current contract would reject.
|
|
1450
|
+
§recorded-emissions **The parser is regressed against emissions models actually produced, not fixtures we wrote.** `test/fixtures/recorded-emissions.jsonl` holds one real exemplar of every distinct parse shape observed across the live and demo drills — the operations authored, whether outside text appeared, and the status the engine recorded at the time. A fixture encodes what we believe a model emits; a recording encodes what one did, so only recordings test the shapes models actually produce (#802, #809).
|
|
1451
|
+
|
|
1452
|
+
| Fact | Rule |
|
|
1453
|
+
| --- | --- |
|
|
1454
|
+
| Shape coverage, not volume | 120 exemplars are ~60 KB against ~88 MB for every emission ever recorded |
|
|
1455
|
+
| The recorded status | **provenance, never an assertion**: the contract has changed under these turns and will again, so the replay asserts only that today's parser still reads each emission the way the corpus says it does |
|
|
1456
|
+
| Regeneration | `scriptify/extract-emission-corpus.ts --write` after a drill; a changed shape is the contract moving and the diff names every shape that moved with it; the extractor also reports how many recorded turns concluded in a way the current contract would reject |
|
|
1396
1457
|
|
|
1397
1458
|
## 12. Public API
|
|
1398
1459
|
|
|
1460
|
+
<!-- map -->
|
|
1461
|
+
| Tag | Promise |
|
|
1462
|
+
| --- | --- |
|
|
1463
|
+
| {§turn-shape} | `PlurnkParser.parse` accepts one model turn. |
|
|
1464
|
+
| {§tier-entrypoints} | Each parser entry point owns one document tier: |
|
|
1465
|
+
| {§runtime-neutral-root} | The package root is runtime-neutral. |
|
|
1466
|
+
| {§root-value-api} | The package-root runtime namespace is closed. |
|
|
1467
|
+
| {§parser-construction-boundary} | Parser construction components are internal rather than alternate consumer entry points: |
|
|
1468
|
+
<!-- /map -->
|
|
1469
|
+
|
|
1399
1470
|
The package root is the single JavaScript and TypeScript entry point for the language and wire
|
|
1400
1471
|
contracts ({§runtime-neutral-root}). Shared AST and wire types come from generated schemas; the small hand-maintained parser
|
|
1401
1472
|
types cover ordered parse items and `PlurnkParseError`, which JSON Schema cannot
|
|
@@ -1453,7 +1524,7 @@ among them: the parser is `@plurnk/plurnk-parser`'s ({§parser-consumers}).
|
|
|
1453
1524
|
| `PathSyntax` | Target-slot spelling and exact-versus-glob classification | {§path-parentheses}, {§path-glob} |
|
|
1454
1525
|
| `TurnDisposition` | The one turn disposition and its recognition | {§turn-disposition} |
|
|
1455
1526
|
| `CapabilityAdmission` | Admission of a capability descriptor against policy layers | {§capability-admission} |
|
|
1456
|
-
| `PLURNK_OPS`, `INTERNAL_ROW_OPS`, `PLURNK_FENCE`
|
|
1527
|
+
| `PLURNK_OPS`, `isPlurnkOp`, `INTERNAL_ROW_OPS`, `PLURNK_FENCE` | The closed operation alphabet, its membership test, and the language's fence | {§canonical-statement} |
|
|
1457
1528
|
| `PROPOSAL_POLICIES` | Server proposal disposition vocabulary | {§proposal-policy} |
|
|
1458
1529
|
| `WORKER_NAME` | Authority minting predicate | {§worker-name} |
|
|
1459
1530
|
| `UNKNOWN_POSITION` | Frozen sentinel for an AST statement without retained parsed source | {§parser-position} |
|
|
@@ -1473,9 +1544,35 @@ than alternate consumer entry points:
|
|
|
1473
1544
|
|
|
1474
1545
|
## 13. Runtime-neutral wire contracts
|
|
1475
1546
|
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1547
|
+
<!-- map -->
|
|
1548
|
+
| Tag | Promise |
|
|
1549
|
+
| --- | --- |
|
|
1550
|
+
| {§wire-entrypoint} | The package root exports generated wire types, `Problems`, `Validator` and the value guards `isRecord`,… |
|
|
1551
|
+
| {§text-region} | 13.1 Text regions |
|
|
1552
|
+
| {§range-extent} | 13.2 Range extents |
|
|
1553
|
+
| {§entry-read-result} | 13.3 Client entry reads |
|
|
1554
|
+
| {§operation-result} | Every public PLURNK operation returns one `OperationResult`: |
|
|
1555
|
+
| {§diagnostic-observation} | A diagnostic says what happened, never why. |
|
|
1556
|
+
| {§problem-details} | `ProblemDetails` requires `type`, `title`, `status`, and `detail`; `instance` is optional until a durable… |
|
|
1557
|
+
| {§problem-error-carrier} | `Problems.fromError(error)` recognizes existing failure carriers without depending on a producer's exception… |
|
|
1558
|
+
| {§problem-projection} | `ProblemProjection` is the sole compact model-packet view of an exact `ProblemDetails`. |
|
|
1559
|
+
| {§notice} | A `Notice` is a transient, nonterminal observation. |
|
|
1560
|
+
| {§notice-directive} | A Notice's `message` states what happened ({§diagnostic-observation}). |
|
|
1561
|
+
| {§client-display-capabilities} | 13.7 Client display capabilities |
|
|
1562
|
+
| {§mcp-server-definition} | 13.8 MCP server definitions |
|
|
1563
|
+
| {§mcp-oauth} | `McpOAuth` is the client-managed OAuth plurnk holds for one Streamable HTTP server, included in that server's… |
|
|
1564
|
+
| {§application-port} | 13.9 Exterior application port |
|
|
1565
|
+
| {§application-worker-observation} | Worker observation exposes identity, lineage, kind and lifecycle; it is neither a client binding nor a… |
|
|
1566
|
+
| {§loop-lifecycle-vocabulary} | One projection maps a loop's durable status onto the lifecycle words every client renders, shared by the… |
|
|
1567
|
+
| {§list-excerpt} | A list shows a message by its excerpt. |
|
|
1568
|
+
| {§application-worker-overview} | The worker overview is the places in a scope with what waits there. |
|
|
1569
|
+
| {§application-loop-observation} | Loop observation exposes the durable scheduler state of work loops (excluding maintenance-only administrative… |
|
|
1570
|
+
<!-- /map -->
|
|
1571
|
+
|
|
1572
|
+
§wire-entrypoint The package root exports generated wire types, `Problems`, `Validator` and
|
|
1573
|
+
the value guards `isRecord`, `isSafeInteger` and `errnoCode` alongside the AST types. Their owning
|
|
1574
|
+
JSON Schemas are published through `@plurnk/plurnk-contracts/schema/*.json`, not re-exported
|
|
1575
|
+
as root values.
|
|
1479
1576
|
|
|
1480
1577
|
### §text-region 13.1 Text regions
|
|
1481
1578
|
|
|
@@ -1529,9 +1626,9 @@ scope, or other persistence columns.
|
|
|
1529
1626
|
|
|
1530
1627
|
| `ClientEntry` field | Contract |
|
|
1531
1628
|
|---------------------|----------------------------------------------------------------------------------------------|
|
|
1532
|
-
| `entryId` | Positive durable entry identifier
|
|
1629
|
+
| `entryId` | Positive durable entry identifier, or `null` for a representation core computes rather than stores |
|
|
1533
1630
|
| `target` | Client selector for the resolved entry, with any channel fragment removed |
|
|
1534
|
-
| `channels` | Every channel for a full read, or exactly the selected channel for a sliced read
|
|
1631
|
+
| `channels` | Every channel for a full read, or exactly the selected channel for a sliced read, by name; the empty name is the unnamed default channel of a scheme whose default is unnamed, a log row's |
|
|
1535
1632
|
|
|
1536
1633
|
| Channel field | Contract |
|
|
1537
1634
|
|-----------------|---------------------------------------------------------------------------------------------------------------|
|
|
@@ -1672,7 +1769,9 @@ authentication fields replace together ({§configuration-definition-resolution})
|
|
|
1672
1769
|
HTTP server, included in that server's `authorization`. Interactive OAuth always requires a callback URL, and
|
|
1673
1770
|
its structurally exclusive identity modes are an HTTPS Client ID Metadata Document URL,
|
|
1674
1771
|
a pre-registered client ID with a symbolic secret, or neither for server-advertised
|
|
1675
|
-
Dynamic Client Registration.
|
|
1772
|
+
Dynamic Client Registration. Any interactive mode may name the `issuer` its sign-in binds to,
|
|
1773
|
+
where discovery starts, and `authorizationParams` added to the authorization request; the
|
|
1774
|
+
parameters the flow sets itself cannot be named. A client-credentials grant names its client ID and
|
|
1676
1775
|
symbolic secret, optionally binding an issuer. Every secret is one complete `${NAME}`
|
|
1677
1776
|
reference to the operator environment; `Validator.assertMcpOAuth` validates the shape.
|
|
1678
1777
|
|
|
@@ -1723,28 +1822,40 @@ each reply's `answers` addresses (empty for incoming messages).
|
|
|
1723
1822
|
`resolveClientInteraction` may carry the accepted answer's message evidence;
|
|
1724
1823
|
Core validates the resolution, retains the arrival, then resumes the operation.
|
|
1725
1824
|
|
|
1726
|
-
§application-worker-observation Worker observation exposes durable identity,
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
hides unfinished work. Maintenance-only loops do not change this projection;
|
|
1734
|
-
their ordinary turns and results remain durable history. `readWorker` resolves exactly one id or name and returns
|
|
1735
|
-
`null` when absent. `listWorkers` filters collections by origin or lineage
|
|
1736
|
-
position; an omitted parent filter means every position and an explicit `null`
|
|
1737
|
-
means roots. Singular and plural cardinalities are distinct contracts.
|
|
1738
|
-
Observation is not a client binding or permission grant; a client renders kind
|
|
1739
|
-
and lifecycle, it never infers them.
|
|
1825
|
+
§application-worker-observation **Worker observation exposes identity, lineage, kind and lifecycle; it is neither a client binding nor a permission grant.** It exposes durable identity, origin, immediate parent identity, minted `kind` (`root` for a worker with no parent; `fork` for a child carrying a fork boundary; `work` for any other child), and `lifecycle`, the worker's representative work loop projected through {§loop-lifecycle-vocabulary} (`idle` when it has none), and `hidden_at`, when the worker was hidden ({§place-hiding}), null while it is shown. A client renders kind and lifecycle, it never infers them.
|
|
1826
|
+
|
|
1827
|
+
| Fact | Rule |
|
|
1828
|
+
| --- | --- |
|
|
1829
|
+
| `selectWorkerLoop` | chooses running before parked before queued; ties select the oldest unresolved sequence; with no live work, the latest terminal settlement wins (sequence breaks equal timestamps); newer terminal history never hides unfinished work; maintenance-only loops do not change this projection, and their ordinary turns and results remain durable history |
|
|
1830
|
+
| `readWorker` | resolves exactly one id or name and returns `null` when absent |
|
|
1831
|
+
| `listWorkers` | filters collections by origin, lineage position or mark; an omitted parent filter means every position and an explicit `null` means roots; an omitted `hidden` means shown and hidden workers alike; singular and plural cardinalities are distinct contracts |
|
|
1740
1832
|
|
|
1741
1833
|
§loop-lifecycle-vocabulary One projection maps a loop's durable status onto the
|
|
1742
1834
|
lifecycle words every client renders, shared by the status gauge and the worker
|
|
1743
|
-
directory: no loop `idle`; 100 `queued`; 102 `running`; 202 `parked`;
|
|
1744
|
-
|
|
1745
|
-
|
|
1835
|
+
directory: no loop `idle`; 100 `queued`; 102 `running`; 202 `parked`; any other status is a
|
|
1836
|
+
concluded loop's: below 400 `completed`; 499 `cancelled`, a loop stopped without failing
|
|
1837
|
+
({§agui-run-outcome}); any other of 400 or more `failed` (413 budget, 429 turn ceiling, 500 fail,
|
|
1838
|
+
504 execution timeout, 508 runaway). `lifecycleOfLoopStatus`
|
|
1746
1839
|
in `@plurnk/plurnk-contracts` is that projection's one owner.
|
|
1747
1840
|
|
|
1841
|
+
§list-excerpt **A list shows a message by its excerpt.** The excerpt is the message's first line holding anything but
|
|
1842
|
+
blanks (spaces, tabs and line ends), cut to at most N characters, a character never cut in two, with blanks trimmed from
|
|
1843
|
+
its end; `continued` says whether anything but blanks follows. `excerptOf` in `@plurnk/plurnk-contracts` is that rule's one
|
|
1844
|
+
owner, for a loop's opening in a worker's loop list ({§agui-worker-loops}) and a worker's latest finished reply
|
|
1845
|
+
({§worker-finished-reply}).
|
|
1846
|
+
|
|
1847
|
+
§application-worker-overview **The worker overview is the places in a scope with what waits there.** A place is a
|
|
1848
|
+
model-origin worker; bookkeeping workers are not places. The scope is the daemon or one workspace; hidden places are out
|
|
1849
|
+
of it ({§place-hiding}).
|
|
1850
|
+
|
|
1851
|
+
| Fact | Rule |
|
|
1852
|
+
| --- | --- |
|
|
1853
|
+
| A place | `{ workspaceId, id, name, parentWorkerId, kind, lifecycle, gates, reply }`: `kind` and `lifecycle` as {§application-worker-observation} projects them, `gates` the proposals and client interactions it waits on as `pendingProposals` and `pendingClientInteractions` project them, `reply` its latest finished reply or `null` |
|
|
1854
|
+
| A reply | `{ id, coordinate, completion, at, excerpt, continued }`: its durable log row, `L/T/S` in its worker's log, the completion its receipt records, when it was recorded (Unix milliseconds) and its excerpt ({§list-excerpt}) |
|
|
1855
|
+
| Order | most recently finished first, by reply row (the log's commit order, so two replies never tie), then the places with no reply, newest first |
|
|
1856
|
+
| Bound | every place waiting on a gate, then the first `limit` in that order; `omitted` counts the places in scope it leaves out, so no place is left out silently |
|
|
1857
|
+
| Workspaces | `{ id, name, projectRoot, projectLabel }` for each workspace a held place belongs to ({§workspace-label}) |
|
|
1858
|
+
|
|
1748
1859
|
§application-loop-observation Loop observation exposes the durable scheduler
|
|
1749
1860
|
state of work loops (excluding maintenance-only administrative loops), nullable
|
|
1750
1861
|
`waitUntil` (the durable observation deadline in Unix milliseconds), the times a loop first
|
|
@@ -1759,6 +1870,30 @@ events or persistence; events remain the live notification edge.
|
|
|
1759
1870
|
|
|
1760
1871
|
## 14. Parse diagnostics
|
|
1761
1872
|
|
|
1873
|
+
<!-- map -->
|
|
1874
|
+
| Tag | Promise |
|
|
1875
|
+
| --- | --- |
|
|
1876
|
+
| {§parse-diagnostics} | `PlurnkParseError` is a JSON-serializable Error subclass. |
|
|
1877
|
+
| {§parse-admission} | A diagnostic's severity does not describe whether an operation ran. |
|
|
1878
|
+
| {§parse-recovery} | Every hard diagnostic carries its working form. |
|
|
1879
|
+
| {§parser-position} | Parser source locations are points, not text regions. |
|
|
1880
|
+
| {§inline-flag-tolerance} | PCRE inline modifiers. |
|
|
1881
|
+
| {§regex-trailing-text} | A valid `/pattern/flags` prefix followed by horizontal whitespace and trailing text receives one concise… |
|
|
1882
|
+
| {§regex-sed-range} | A sed line range is named as one. |
|
|
1883
|
+
| {§unclosed-regex} | A regex that never closes. |
|
|
1884
|
+
| {§naked-pattern} | The matcher rides the heading bare. |
|
|
1885
|
+
| {§trailing-slots} | Slots after the matcher peel off the right. |
|
|
1886
|
+
| {§log-heading-notation} | The log's heading notation, copied as syntax, is read as the slot it stands for. |
|
|
1887
|
+
| {§bare-target} | A target written without its parentheses is refused with the line that runs. |
|
|
1888
|
+
| {§bare-anchor-scope} | An EDIT's anchor without its angle brackets is its scope. |
|
|
1889
|
+
| {§matcher-body-redirect} | Unread selector text. |
|
|
1890
|
+
| {§combined-anchor-tolerance} | Combined line number and anchor in a scope. |
|
|
1891
|
+
| {§invalid-scope-diagnostic} | Malformed scope content. |
|
|
1892
|
+
| {§error-shape} | The diagnostic class determines the parts of a message; every class says what happened, never why… |
|
|
1893
|
+
| {§parse-attempt} | A hard fact that refused a statement the parser opened carries its `attempt`: the statement's text exactly as… |
|
|
1894
|
+
| {§unparsed-tail-boundary} | When the lexer cannot determine where a malformed statement ends — an unfinished `(target` or `[metadata`… |
|
|
1895
|
+
<!-- /map -->
|
|
1896
|
+
|
|
1762
1897
|
§parse-diagnostics `PlurnkParseError` is a JSON-serializable Error subclass.
|
|
1763
1898
|
Its `message` contains only the parser-owned diagnostic; position, source, and
|
|
1764
1899
|
severity remain separate facts.
|
|
@@ -1864,49 +1999,24 @@ diagnostics are:
|
|
|
1864
1999
|
it has no pattern to read and is refused as `invalid-operation-syntax` naming what
|
|
1865
2000
|
is missing. A matcher with a second unescaped `/` is not unclosed: it is
|
|
1866
2001
|
`/pattern/flags`, and invalid flags keep their native failure with the escape hint.
|
|
1867
|
-
- §naked-pattern **The matcher rides the heading bare.** After the path, and any
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
`FIND (src/parser.ts) /\bparse\w+\b/` is the same operation as
|
|
1886
|
-
`FIND (src/parser.ts) [{"pattern": "/\\bparse\\w+\\b/"}]`. `^` claims the regex
|
|
1887
|
-
dialect without slashes or flags: the whole text is the pattern, so
|
|
1888
|
-
`READ (notes.md) ^Decision:.*` selects lines beginning with `Decision:`.
|
|
1889
|
-
`^` is deliberately absent from `plurnk.md`'s dialect table: a model writes the anchor
|
|
1890
|
-
whether or not it is taught, so the engine honours it without spending hot-path teaching
|
|
1891
|
-
on it. The omission is not drift between the teaching and the engine.
|
|
1892
|
-
- §trailing-slots **Slots after the matcher peel off the right.** The heading text after
|
|
1893
|
-
the matcher is read backwards: a trailing `<!-- aside -->`, a trailing `<scope>` in the
|
|
1894
|
-
shapes the lexer admits (result positions on FIND, text coordinates elsewhere) and a
|
|
1895
|
-
trailing `[option block]` that parses as an array of objects come off the right end in
|
|
1896
|
-
any order, each taken once and only when the heading did not already carry that slot,
|
|
1897
|
-
until what remains is the matcher. `READ (a.rs) /fn resolve_/ <1,-1> <!-- entities -->`
|
|
1898
|
-
is the same operation as `READ (a.rs) <1,-1> /fn resolve_/ <!-- entities -->`, with
|
|
1899
|
-
one warning-severity advisory naming the canonical order for the scope or block:
|
|
1900
|
-
recovery requires a single possible path-slot owner. With multiple slots, a trailing scope
|
|
1901
|
-
or metadata block refuses the heading rather than relocating or discarding the slot.
|
|
1902
|
-
A matcher that
|
|
1903
|
-
itself ends in one of those shapes takes the option escape.
|
|
1904
|
-
`plurnk.md` teaches one order — `OP (path)? <scope|range>? [metadata]? pattern?
|
|
1905
|
-
<!-- aside -->?` — and free ordering is not taught. Small departure, small
|
|
1906
|
-
reinterpretation ({§outside-text}): every slot the model wrote is present and
|
|
1907
|
-
unambiguous, so only their sequence differs from the taught form, and nothing is
|
|
1908
|
-
invented to read it. The advisory names the canonical order rather than refusing,
|
|
1909
|
-
because the operation the model meant is never in doubt.
|
|
2002
|
+
- §naked-pattern **The matcher rides the heading bare.** After the path, and any scope or option block, the rest of a FIND, READ or KILL heading line is the matcher, in whichever dialect its first characters claim ({§matcher-prefix-claims}): `/re/i`, `^anchored`, `//xpath`, `$.json`, `~words`, `&symbol`, or a sigil-less glob or literal such as `TODO` or `*.ts`. `FIND (src/parser.ts) /\bparse\w+\b/` is the same operation as `FIND (src/parser.ts) [{"pattern": "/\\bparse\\w+\\b/"}]`: the lift is exactly what `[{"pattern": "…"}]` produces, and that option remains the escape for a matcher the heading cannot hold bare — one opening with `(`, `<`, `[` or a backtick, one containing `<!--`, and every COPY/MOVE operand.
|
|
2003
|
+
|
|
2004
|
+
| Fact | Rule |
|
|
2005
|
+
| --- | --- |
|
|
2006
|
+
| Not a matcher | `#name` alone, a `#` followed by one channel token and nothing else, after a target that names no channel, is that target's channel exactly as if written on the path ({§local-path-fragment}); a target that already names a channel keeps such a token as its pattern |
|
|
2007
|
+
| Independence | heading matchers remain independent of owner options: a block without `pattern` never erases the heading matcher, and invalid blocks still reach the owning validator; their heading-line text owns selection independently of annotation or distillation bodies |
|
|
2008
|
+
| EDIT | only a sigil lifts, because plain heading-line text is the replacement body it always was; the lines beneath the heading are then the replacement, and none deletes each match ({§edit-pattern}) |
|
|
2009
|
+
| The aside | a trailing `<!-- aside -->` on the same line stays the aside |
|
|
2010
|
+
| `^` | claims the regex dialect without slashes or flags: the whole text is the pattern, so `READ (notes.md) ^Decision:.*` selects lines beginning with `Decision:`; `^` is deliberately absent from `plurnk.md`'s dialect table — a model writes the anchor whether or not it is taught, so the engine honours it without spending hot-path teaching on it, and the omission is not drift between the teaching and the engine |
|
|
2011
|
+
|
|
2012
|
+
- §trailing-slots **Slots after the matcher peel off the right.** The heading text after the matcher is read backwards: a trailing `<!-- aside -->`, a trailing `<scope>` in the shapes the lexer admits (result positions on FIND, text coordinates elsewhere) and a trailing `[option block]` that parses as an array of objects come off the right end in any order, each taken once and only when the heading did not already carry that slot, until what remains is the matcher. `READ (a.rs) /fn resolve_/ <1,-1> <!-- entities -->` is the same operation as `READ (a.rs) <1,-1> /fn resolve_/ <!-- entities -->`, with one warning-severity advisory naming the canonical order for the scope or block.
|
|
2013
|
+
|
|
2014
|
+
| Fact | Rule |
|
|
2015
|
+
| --- | --- |
|
|
2016
|
+
| Recovery | requires a single possible path-slot owner: with multiple slots, a trailing scope or metadata block refuses the heading rather than relocating or discarding the slot |
|
|
2017
|
+
| A matcher that itself ends in one of those shapes | takes the option escape |
|
|
2018
|
+
| Teaching | `plurnk.md` teaches one order — `OP (path)? <scope\|range>? [metadata]? pattern? <!-- aside -->?` — and free ordering is not taught; small departure, small reinterpretation ({§outside-text}): every slot the model wrote is present and unambiguous, so only their sequence differs from the taught form, and nothing is invented to read it; the advisory names the canonical order rather than refusing, because the operation the model meant is never in doubt |
|
|
2019
|
+
|
|
1910
2020
|
- §log-heading-notation **The log's heading notation, copied as syntax, is read as the slot it
|
|
1911
2021
|
stands for.** A packet's log row heading is `### log:///L/T/S/OP → path pattern · N`
|
|
1912
2022
|
({§log-wire-format} in the core SPEC); models copy its notation onto their own headings. Each
|