@plurnk/plurnk-contracts 1.17.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.defaults +11 -0
- package/README.md +10 -43
- package/SPEC.md +363 -280
- package/dist/conformance/agui-v1.json +3 -50
- package/dist/schema/CapabilityDescriptor.json +6 -1
- package/dist/schema/CapabilitySelector.json +6 -1
- package/dist/schema/ClientStatement.json +0 -10
- package/dist/schema/FunctionalityDefinitionState.json +9 -1
- package/dist/schema/LoopPolicy.json +32 -3
- package/dist/schema/LoopPolicyRequest.json +16 -0
- package/dist/schema/McpConfigurationOverlay.json +1 -14
- package/dist/schema/McpServerDefinition.json +1 -1
- package/dist/schema/PlurnkStatement.json +30 -41
- package/dist/schema/ProposalProjection.json +6 -2
- package/dist/schema/SkillDefinition.json +3 -3
- package/dist/schema/TextLineMarker.json +1 -1
- package/dist/src/ApplicationPort.d.ts +38 -10
- package/dist/src/ApplicationPort.d.ts.map +1 -1
- package/dist/src/LoopLifecycle.d.ts +5 -0
- package/dist/src/LoopLifecycle.d.ts.map +1 -1
- package/dist/src/LoopLifecycle.js +15 -0
- package/dist/src/LoopLifecycle.js.map +1 -1
- package/dist/src/MessageResource.d.ts +30 -0
- package/dist/src/MessageResource.d.ts.map +1 -0
- package/dist/src/MessageResource.js +2 -0
- package/dist/src/MessageResource.js.map +1 -0
- package/dist/src/PlurnkParseError.d.ts +1 -3
- package/dist/src/PlurnkParseError.d.ts.map +1 -1
- package/dist/src/PlurnkParseError.js +1 -4
- package/dist/src/PlurnkParseError.js.map +1 -1
- package/dist/src/Problems.d.ts +1 -0
- package/dist/src/Problems.d.ts.map +1 -1
- package/dist/src/Problems.js +19 -1
- package/dist/src/Problems.js.map +1 -1
- package/dist/src/TurnDisposition.d.ts +3 -4
- package/dist/src/TurnDisposition.d.ts.map +1 -1
- package/dist/src/TurnDisposition.js +5 -21
- package/dist/src/TurnDisposition.js.map +1 -1
- package/dist/src/Validator.d.ts +3 -3
- package/dist/src/Validator.d.ts.map +1 -1
- package/dist/src/Validator.js +14 -15
- package/dist/src/Validator.js.map +1 -1
- package/dist/src/index.d.ts +3 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/types.d.ts +15 -6
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.generated.d.ts +60 -76
- package/dist/src/types.generated.d.ts.map +1 -1
- package/dist/src/types.js +19 -12
- package/dist/src/types.js.map +1 -1
- package/package.json +7 -20
- package/plurnk.md +49 -73
- package/bin/plurnk-contracts.js +0 -43
- package/dist/schema/AcpPlan.json +0 -63
- package/dist/schema/Plan.json +0 -65
- package/dist/src/AcpPlanValue.d.ts +0 -6
- package/dist/src/AcpPlanValue.d.ts.map +0 -1
- package/dist/src/AcpPlanValue.js +0 -36
- package/dist/src/AcpPlanValue.js.map +0 -1
- package/dist/src/AstBuilder.d.ts +0 -21
- package/dist/src/AstBuilder.d.ts.map +0 -1
- package/dist/src/AstBuilder.js +0 -876
- package/dist/src/AstBuilder.js.map +0 -1
- package/dist/src/PlanValue.d.ts +0 -9
- package/dist/src/PlanValue.d.ts.map +0 -1
- package/dist/src/PlanValue.js +0 -63
- package/dist/src/PlanValue.js.map +0 -1
- package/dist/src/PlurnkErrorStrategy.d.ts +0 -11
- package/dist/src/PlurnkErrorStrategy.d.ts.map +0 -1
- package/dist/src/PlurnkErrorStrategy.js +0 -253
- package/dist/src/PlurnkErrorStrategy.js.map +0 -1
- package/dist/src/PlurnkParser.d.ts +0 -15
- package/dist/src/PlurnkParser.d.ts.map +0 -1
- package/dist/src/PlurnkParser.js +0 -330
- package/dist/src/PlurnkParser.js.map +0 -1
- package/dist/src/RecordingListener.d.ts +0 -9
- package/dist/src/RecordingListener.d.ts.map +0 -1
- package/dist/src/RecordingListener.js +0 -37
- package/dist/src/RecordingListener.js.map +0 -1
- package/dist/src/generated/plurnkLexer.d.ts +0 -162
- package/dist/src/generated/plurnkLexer.d.ts.map +0 -1
- package/dist/src/generated/plurnkLexer.js +0 -1060
- package/dist/src/generated/plurnkLexer.js.map +0 -1
- package/dist/src/generated/plurnkParser.d.ts +0 -436
- package/dist/src/generated/plurnkParser.d.ts.map +0 -1
- package/dist/src/generated/plurnkParser.js +0 -2972
- package/dist/src/generated/plurnkParser.js.map +0 -1
- package/dist/src/generated/plurnkParserVisitor.d.ts +0 -263
- package/dist/src/generated/plurnkParserVisitor.d.ts.map +0 -1
- package/dist/src/generated/plurnkParserVisitor.js +0 -227
- package/dist/src/generated/plurnkParserVisitor.js.map +0 -1
package/SPEC.md
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## 1. Overview
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
is the single code API for those contracts
|
|
5
|
+
This package is the single authority for PLURNK's language, schemas, generated types and
|
|
6
|
+
runtime-neutral wire envelopes; `@plurnk/plurnk-parser` implements the language it specifies
|
|
7
|
+
({§parser-consumers}). Its package root is the single code API for those contracts
|
|
8
|
+
({§root-value-api}).
|
|
8
9
|
|
|
9
10
|
| Surface | Canonical export or artifact |
|
|
10
11
|
| ------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
11
|
-
|
|
|
12
|
-
| Capability and loop policies
|
|
12
|
+
| AST, validators, Problems, results, Notices, text regions and extents | `@plurnk/plurnk-contracts` |
|
|
13
|
+
| Capability and loop policies | `CapabilityPolicy`, `LoopPolicy`, `LoopPolicyRequest`, `PROPOSAL_POLICIES` |
|
|
13
14
|
| Durable reasoning intent | `ReasoningPolicy`, `REASONING_POLICIES` |
|
|
14
15
|
| Model route and catalog discovery | `ModelRoute`, `ModelCatalogQuery`, `ModelCatalogPage`, `ModelReadiness` |
|
|
15
16
|
| Stopped-world client contract | `ProposalDisposition`, `ProposalProjection` |
|
|
@@ -89,12 +90,10 @@ and previews; never reformat literal resources, JSONL framing, or wire/evidence
|
|
|
89
90
|
serialization. Compact aggregate rows ({§json-result-rendering}) and packet
|
|
90
91
|
metadata retain their deliberate layouts.
|
|
91
92
|
|
|
92
|
-
##
|
|
93
|
+
## 1.1 Contract layers and admission boundary
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
teaching, and an operator's sampling grammar admitting a sentence does not
|
|
97
|
-
make its runtime semantics valid.
|
|
95
|
+
One contract, deliberately different projections (ARCHITECTURE.md). Each layer
|
|
96
|
+
below owns what it alone can decide.
|
|
98
97
|
|
|
99
98
|
```mermaid
|
|
100
99
|
flowchart LR
|
|
@@ -127,7 +126,7 @@ WHATWG `URL`, ECMAScript `RegExp`, XPath 1.0, and RFC 9535 JSONPath parsers.
|
|
|
127
126
|
The runtime owner decides facts that require state or operation-specific
|
|
128
127
|
meaning, including registered scheme resolution, target existence, tag
|
|
129
128
|
selection, text-region bounds, result ordering, full-text ranking, mutation
|
|
130
|
-
effects, executor behavior
|
|
129
|
+
effects, and executor behavior.
|
|
131
130
|
|
|
132
131
|
### §contract-proposal-projection Loop policy and stopped-world projection
|
|
133
132
|
|
|
@@ -168,11 +167,15 @@ workspace layer and their normalized intersection: `service`, `workspace`, and
|
|
|
168
167
|
capability policy or inherited bound; every actor uses the same live workspace
|
|
169
168
|
policy. A client never derives effective authority from the mutable layer alone.
|
|
170
169
|
|
|
171
|
-
§loop-policy `
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
§loop-policy A `LoopPolicy` is complete and immutable after creation:
|
|
171
|
+
`proposals` chooses one downstream settlement posture and `attended` says
|
|
172
|
+
whether anyone can answer, independently of workspace capability policy. An
|
|
173
|
+
unattended loop cannot hold a proposal for review, so the schema refuses that
|
|
174
|
+
pair. A `LoopPolicyRequest` is the part of a policy its creator chose to state.
|
|
175
|
+
Contracts hold no default for the rest: the daemon's panel supplies it
|
|
176
|
+
({§loop-policy-composition}). `PROPOSAL_POLICIES` is the schema-owned
|
|
177
|
+
vocabulary of `proposals`. Capability admission precedes effect
|
|
178
|
+
classification and proposal settlement.
|
|
176
179
|
|
|
177
180
|
§reasoning-policy-wire `ReasoningPolicy` is exactly `off | adaptive | low |
|
|
178
181
|
medium | high`. The schema owns this shared wire vocabulary. Providers own the
|
|
@@ -255,7 +258,8 @@ and parse diagnostics are separate contracts.
|
|
|
255
258
|
body
|
|
256
259
|
```
|
|
257
260
|
|
|
258
|
-
```OP (path)? <scope
|
|
261
|
+
```OP (path)? <scope>?
|
|
262
|
+
```
|
|
259
263
|
|
|
260
264
|
```executor (program-or-tool)?
|
|
261
265
|
input
|
|
@@ -263,37 +267,56 @@ input
|
|
|
263
267
|
`````
|
|
264
268
|
|
|
265
269
|
§section-boundary Every statement is one backtick block. Its header occupies one
|
|
266
|
-
physical line: a fence of at least
|
|
270
|
+
physical line: a fence of at least four backticks ({§four-backtick-operations}), an optional numeric delimiter
|
|
267
271
|
({§numeric-delimiter}), then the name and its slots. A closer is shown by
|
|
268
272
|
convention and never demanded ({§fence-closer}, {§closer-fallback}). There are no
|
|
269
|
-
operation suffixes or heading levels.
|
|
270
|
-
|
|
271
|
-
characters (operator, 2026-09-12: counted pairs failed 52 of 363 turns on
|
|
272
|
-
GLM-5.3-flash; anchored tokens failed none).
|
|
273
|
+
operation suffixes or heading levels. Complete nested matches take precedence
|
|
274
|
+
over local recovery ({§balanced-fences}).
|
|
273
275
|
|
|
274
276
|
§fence-closer A block opened with N backticks and delimiter D (its digits, possibly
|
|
275
|
-
none) closes at the first line
|
|
277
|
+
none) closes at the first unclaimed line made of at least N backticks,
|
|
276
278
|
exactly D, and nothing else but horizontal whitespace. Count follows CommonMark: a
|
|
277
279
|
shorter fence inside the body is body; an equal or longer bare fence closes a bare
|
|
278
|
-
block
|
|
280
|
+
block unless it closes a balanced nested block ({§balanced-fences}). The delimiter
|
|
281
|
+
compares exactly: a bare fence never closes a delimited block,
|
|
279
282
|
and a delimited fence never closes a bare one. The compact one-line form closes on
|
|
280
283
|
its heading line after the modifiers under the same rule.
|
|
281
284
|
|
|
285
|
+
§balanced-fences A complete nested interpretation takes precedence over missing-closer
|
|
286
|
+
recovery. Within an undelimited body, line-leading labeled fences open literal
|
|
287
|
+
blocks; their matching closers close the innermost block first. The enclosing
|
|
288
|
+
block and its nested blocks must all close, with matching widths and delimiters
|
|
289
|
+
under {§fence-closer}. Equal opener/closer totals alone are insufficient. A complete
|
|
290
|
+
inline block is already closed; a numerically delimited block is opaque until its
|
|
291
|
+
own closer. Preserve every nested body byte, including apparent OPs and known
|
|
292
|
+
executors, without dispatching them. If no complete enclosing interpretation exists,
|
|
293
|
+
retain {§fence-heading-in-body} and {§closer-fallback}. These rules apply equally to
|
|
294
|
+
model programs, stored programs, client operations, and reasoning quotations.
|
|
295
|
+
|
|
282
296
|
§numeric-delimiter Digits between the opening backticks and the name (an opener
|
|
283
|
-
carrying `42EDIT (x)`) identify the block, and only a fence carrying `42` closes it.
|
|
284
|
-
|
|
285
|
-
|
|
297
|
+
carrying `42EDIT (x)`) identify the block, and only a fence carrying `42` closes it.
|
|
298
|
+
This explicitly protects bare fences and headings, including incomplete examples.
|
|
299
|
+
The delimiter is syntax, never AST or persistence
|
|
286
300
|
state; `PlurnkParser.frame` chooses one when the body it wraps holds a heading line
|
|
287
301
|
of four or more backticks ({§statement-rendering}).
|
|
288
302
|
|
|
289
|
-
§
|
|
290
|
-
|
|
291
|
-
|
|
303
|
+
§four-backtick-operations **An operation opens with four backticks.** A heading is a fence of
|
|
304
|
+
four or more backticks; a three-backtick fence is markdown wherever it stands, so an answer's
|
|
305
|
+
code blocks (```` ```sh ````, ```` ```ts ````) are prose and never run (operator,
|
|
306
|
+
2026-09-18, #761). A three-backtick fence naming an operation or known executor draws one warning that it
|
|
307
|
+
needs four backticks; any other three-backtick fence draws none. `plurnk.md` teaches exactly
|
|
308
|
+
four; longer fences are tolerated, not taught. Every producer of a statement — the parser, a
|
|
309
|
+
client composing `/look`, a client's tab-completion — writes `PLURNK_FENCE` rather than its own
|
|
310
|
+
literal, so no surface can ship a width the parser will quote (plurnk/plurnk#92).
|
|
311
|
+
|
|
312
|
+
§fence-heading-in-body Outside a complete nested block ({§balanced-fences}), a fence
|
|
313
|
+
line of four or more backticks, optional digits, and a name that is a native operation
|
|
314
|
+
or a known executor is a heading. Inside an open block it ends that block without closing it
|
|
292
315
|
({§closer-fallback}) and opens the next statement. Fence lines of fewer than four
|
|
293
|
-
backticks are headings
|
|
316
|
+
backticks are never headings ({§four-backtick-operations}). Known executors are `sh` plus what
|
|
294
317
|
the host names in `ParseOptions.executors`. Consequences: a closer glued to the next
|
|
295
|
-
opener (eight backticks then `READ`) can never swallow
|
|
296
|
-
|
|
318
|
+
opener (eight backticks then `READ`) can never swallow an unbalanced turn, and a numeric
|
|
319
|
+
delimiter preserves quoted headings even when their own fences are incomplete.
|
|
297
320
|
|
|
298
321
|
§closer-fallback A block that ends at a heading or at the end of the input has no
|
|
299
322
|
closer of its own. Its body is cut back to its last bare fence line (any count,
|
|
@@ -302,48 +325,67 @@ ending goes with it; when no bare fence line exists the body is the whole span l
|
|
|
302
325
|
one terminating line ending. This carries no diagnostic: a missing closer is never
|
|
303
326
|
an admission failure, and {§unparsed-tail-boundary} is not involved.
|
|
304
327
|
|
|
305
|
-
§fence-boundary
|
|
306
|
-
|
|
328
|
+
§fence-boundary Balanced nesting is resolved before local recovery. Otherwise,
|
|
329
|
+
fences are read by count and delimiter, except for the heading rule above:
|
|
307
330
|
|
|
308
331
|
| Fence encountered inside a body | Meaning |
|
|
309
332
|
|---|---|
|
|
333
|
+
| Part of a complete nested block | Literal body, including its openers and closers |
|
|
310
334
|
| Fewer backticks than the block's own | Body |
|
|
311
335
|
| At least the block's backticks, bare, block undelimited | The block's closer |
|
|
312
336
|
| At least the block's backticks carrying the block's delimiter | The block's closer |
|
|
313
337
|
| At least the block's backticks with any other delimiter | Body |
|
|
314
338
|
| Four or more backticks naming a native operation or known executor | A heading: ends the block, opens the next statement |
|
|
315
339
|
|
|
316
|
-
§indented-fences Leading horizontal whitespace before
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
at five to ten percent of emissions on
|
|
340
|
+
§indented-fences Leading horizontal whitespace before a CLOSER is not part of the fence: an
|
|
341
|
+
indented closer, heading-that-ends-a-block, or closer fallback still closes, and a body keeps its
|
|
342
|
+
own lines' indentation. An OPENER is different: an operation's backticks follow a newline
|
|
343
|
+
directly (operator, 2026-09-18), so an indented fence opens a quotation, never an operation —
|
|
344
|
+
CommonMark reads an indented block as code, and `plurnk.md` shows its own examples that way. This
|
|
345
|
+
reverses the 2026-09-12 tolerance (then measured at five to ten percent of emissions on
|
|
346
|
+
GLM-5.3-flash; 2.8% of that lane's emissions today). The cost is paid loudly: an indented fence
|
|
347
|
+
naming a known operation draws `must start its line to run` and is an operation attempt, never an
|
|
348
|
+
answer ({§prose-conclusion}), so the loop continues instead of delivering a program as prose.
|
|
322
349
|
|
|
323
350
|
§inline-chain A closer on a heading line, or on a body's closing line, may be
|
|
324
351
|
followed on that same line by the next opener; the closer still closes, and the
|
|
325
352
|
opener opens. This absorbs the habit of writing several operations in one
|
|
326
|
-
paragraph after prose. Prose after a closer on its line ends the chain
|
|
353
|
+
paragraph after prose. Prose after a closer on its line ends the chain; slot-shaped
|
|
354
|
+
text there is the heading's own and is read under {§transparent-inline-closer}.
|
|
355
|
+
|
|
356
|
+
§transparent-inline-closer **A closer mid-heading is read as if it were not written.** A
|
|
357
|
+
closing fence on a heading line followed by more of that heading — a `<scope>`, an
|
|
358
|
+
`[option block]`, a `<!-- aside -->`, or a naked matcher — does not end the reading: the
|
|
359
|
+
heading keeps taking its slots under {§trailing-slots} and {§naked-pattern}, exactly as though
|
|
360
|
+
the closer were absent, so ````` ````READ (a.md)```` ````` `<1,2>` is the same operation as `READ (a.md) <1,2>`.
|
|
361
|
+
The closer is still a closer: the block ends with that physical line and never reaches down for
|
|
362
|
+
the next operation, which is what a bare heading carrying a matcher would do. A closer followed
|
|
363
|
+
by the next opener is {§inline-chain}, and by nothing is the ordinary {§fence-closer}. There is
|
|
364
|
+
no ambiguity to resolve: a slot begins with `<` or `[` and an opener with a backtick run, so the
|
|
365
|
+
shapes are disjoint (operator, 2026-09-13: "If there is no risk of ambiguity, then we add
|
|
366
|
+
tolerance. Turning model soup into operations instead of errors is a cardinal imperative").
|
|
327
367
|
|
|
328
368
|
§executor-case **An executor tag in any case.** A fence tag that matches a
|
|
329
369
|
registered executor's name case-insensitively opens that executor (`SH` opens
|
|
330
370
|
`sh`), and the statement's `executor` is the registered spelling, so a lookup
|
|
331
371
|
by that name never misses. Operation names stay uppercase by teaching and were
|
|
332
372
|
never written otherwise in 12,000 fences; one `SH` in 1,300 `sh` fences was
|
|
333
|
-
(2026-09-13 census). An unregistered name
|
|
334
|
-
({§interstitial-fence}).
|
|
335
|
-
|
|
336
|
-
§
|
|
337
|
-
|
|
338
|
-
|
|
373
|
+
(2026-09-13 census). An unregistered name without an accepted spelling
|
|
374
|
+
({§executor-js-spelling}) is still prose ({§interstitial-fence}).
|
|
375
|
+
|
|
376
|
+
§executor-js-spelling When `node` is registered and `js` is not, `js` names
|
|
377
|
+
`node` under {§executor-case}. Parsing normalizes the runtime before admission
|
|
378
|
+
and dispatch; execution, policy, receipts, and output addresses remain Node's.
|
|
379
|
+
The authored source remains unchanged. This spelling adds no executor, discovery
|
|
380
|
+
entry, or model-facing teaching. An explicitly registered `js` retains its own
|
|
381
|
+
identity; absent `node`, the shorthand grants no executable capability.
|
|
382
|
+
|
|
383
|
+
§one-line-turn **A whole turn on one line.** A model may emit a turn as a single
|
|
384
|
+
line: prose, then heading after heading with no line ending anywhere. Two
|
|
339
385
|
rules absorb it. The next opener on a heading's own line, after the heading's
|
|
340
386
|
slots, ends that heading's block bodyless and opens ({§empty-section}), so
|
|
341
387
|
`````EDIT (a.rs) <60,66> <!-- drop --> ````EDIT (b.rs) <31,38>` is two scoped
|
|
342
|
-
deletions
|
|
343
|
-
(`````TASK [{"content": "…", "status": "in_progress"}] ````) takes that block as
|
|
344
|
-
its body when nothing sits beneath the heading, with one warning-severity
|
|
345
|
-
advisory naming the body as where the inventory belongs. A block beneath the
|
|
346
|
-
heading still wins.
|
|
388
|
+
deletions. Literal inline bodies follow {§heading-inline-body}.
|
|
347
389
|
|
|
348
390
|
§anchor-digits In a text scope, `@` followed by one to four digits cannot be a
|
|
349
391
|
hash and is read as that line number, with one warning-severity advisory naming
|
|
@@ -353,33 +395,81 @@ the five-character anchor form. Five characters after `@` are always an anchor.
|
|
|
353
395
|
line takes the rest of the line as the aside, with one warning-severity advisory.
|
|
354
396
|
A closed aside followed by more text is unchanged.
|
|
355
397
|
|
|
356
|
-
§
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
398
|
+
§quotation **A fence that opens no operation quotes.** Outside a body, a line-start fence that
|
|
399
|
+
is not an operation heading — unlabeled, tagged like a code block (`ts`, `json`), three
|
|
400
|
+
backticks ({§four-backtick-operations}), indented, or four or more with an unknown name — opens a
|
|
401
|
+
quotation that runs to its matching closer (same character, width at least the opener's) or to
|
|
402
|
+
the end of the input. Everything inside is data: no operation runs there, native tool-call
|
|
403
|
+
markup is not read ({§native-tool-calls}), and no heading draws an advisory. So a model may show
|
|
404
|
+
plurnk's own operations in an answer. Three exceptions keep programs whole:
|
|
405
|
+
CommonMark's own rule that a backtick opener's line carries no further backtick, so
|
|
406
|
+
```` ```READ (x)``` ```` is inline code and quotes nothing after it; a bare fence directly under a
|
|
407
|
+
line carrying a fence run, which is an orphaned closer and quotes nothing; and a tag that is a
|
|
408
|
+
missed operation — a known name under four backticks or off column zero, or an unknown name at
|
|
409
|
+
operation width — which still draws one warning (`markdown` and `md` are polite envelopes and
|
|
410
|
+
draw none). There is no implicit SEND: a reply is prose ({§prose-conclusion}) or an explicit
|
|
411
|
+
`SEND` block. Origin (#767, 2026-09-18): under prose answers, a quoted example executed.
|
|
412
|
+
|
|
413
|
+
§interstitial-fence Superseded by {§quotation}: an unlabeled fence no longer opens nothing, it
|
|
414
|
+
quotes. (It in turn replaced the retired unlabeled-fence SEND of the fences chapter, whose
|
|
415
|
+
unlabeled fences turned displaced headings into silent messages.)
|
|
416
|
+
|
|
417
|
+
§closer-aside A closing fence followed on its line by one aside and nothing else
|
|
418
|
+
is the closer; the aside is outside text. Read as body, that line would be written
|
|
419
|
+
into the edited resource (#758: a recorded EDIT deleting a line wrote
|
|
420
|
+
```` ```` <!-- remove duplicated Result import --> ```` into a Python file). A
|
|
421
|
+
closing fence followed by any other text is still body.
|
|
422
|
+
|
|
423
|
+
§heading-slot-order A heading near-miss with exactly one reading is read as that
|
|
424
|
+
reading, with no diagnostic and no teaching (#758):
|
|
425
|
+
|
|
426
|
+
- an aside written before the heading's remaining scope or JSON option block is
|
|
427
|
+
read after them (`READ (a.md) <!-- why --> <1,-1>`); an aside followed by a
|
|
428
|
+
target or a non-JSON block keeps its place and stays refused;
|
|
429
|
+
- zero-width characters (U+200B–U+200D, U+2060, U+FEFF) on a heading line are skipped;
|
|
430
|
+
- a matcher that begins with a sigil and is quoted in single backticks
|
|
431
|
+
(`` `^def test_` ``) is that matcher; quoted text without a sigil stays refused.
|
|
432
|
+
|
|
433
|
+
Tokens keep their source positions; only their order in the stream changes.
|
|
434
|
+
|
|
435
|
+
§native-tool-calls An emission that yields no operation may be a model's native
|
|
436
|
+
tool-call markup (DeepSeek's `<||DSML|| calls>` block) naming a plurnk operation or
|
|
437
|
+
a known executor. Each `invoke` is read as that operation's canonical fence:
|
|
438
|
+
`path`/`target` fill the target, `scope`/`range`/`lines` the scope, `pattern` a
|
|
439
|
+
matcher option, `aside` the aside, and `body`/`content`/`command` or plain lines
|
|
440
|
+
inside the invoke the body; plurnk slots written after the invoke name are kept.
|
|
441
|
+
Each block keeps its line count, so statement positions still name the source
|
|
442
|
+
line. An invoke with an unknown name or parameter leaves the whole emission as it
|
|
443
|
+
was. An emission that already yields an operation is never rewritten. No
|
|
444
|
+
diagnostic, notice or teaching mentions the reading (#760).
|
|
445
|
+
|
|
446
|
+
§operation-attempt An emission with no operation is either prose, which a host may take
|
|
447
|
+
as the model's answer, or an operation attempt. `PlurnkParser.operationAttempt(input,
|
|
448
|
+
executors)` names the attempt: a line opening a four-backtick fence, a heading outside
|
|
449
|
+
any fence ({§bare-heading-advisory}; a known executor's name is a heading only when a
|
|
450
|
+
slot follows it), native tool-call markup that {§native-tool-calls} did not read, or
|
|
451
|
+
echoed packet rows (`### log://…`). Anything else, three-backtick code blocks included,
|
|
452
|
+
is prose (#761).
|
|
363
453
|
|
|
364
454
|
§bare-heading-advisory An operation name that opens a line outside any block in the
|
|
365
|
-
shape of a heading (`READ (…)`, `
|
|
455
|
+
shape of a heading (`READ (…)`, `NOTE`, …) is prose and runs nothing. The parser
|
|
366
456
|
emits one warning-severity advisory naming the fence form, placed after the parsed
|
|
367
457
|
items, so the loss is never quiet.
|
|
368
458
|
|
|
369
459
|
§empty-section Both the compact bodyless form and an empty multiline block
|
|
370
|
-
normalize optional bodies to null.
|
|
371
|
-
under {§plan-value}. Closing fences are conventional, never required
|
|
460
|
+
normalize optional bodies to null. Closing fences are conventional, never required
|
|
372
461
|
({§closer-fallback}).
|
|
373
462
|
|
|
374
463
|
§statement-rendering `PlurnkParser.stringify` renders native OP names and named
|
|
375
|
-
|
|
464
|
+
runtime fences from the shared AST, with one blank line between operations.
|
|
376
465
|
Every closing fence occupies its own line, including bodyless operations;
|
|
377
466
|
inline fences remain accepted input, not generated examples.
|
|
378
467
|
It chooses at least four backticks and more than any run within the body, and a
|
|
379
468
|
numeric delimiter whenever the body holds a heading line of four or more backticks
|
|
380
469
|
({§fence-heading-in-body}), preserving body bytes on reparse. Fence length and
|
|
381
470
|
delimiter are syntax, not AST or persistence state. Core-authored programs use
|
|
382
|
-
this serializer and the ordinary admission parser.
|
|
471
|
+
this serializer and the ordinary admission parser. Rendering preserves a matcher
|
|
472
|
+
beside owner metadata, not only a matcher carried inside its `pattern` option.
|
|
383
473
|
|
|
384
474
|
| Element | Contract |
|
|
385
475
|
|---|---|
|
|
@@ -398,8 +488,9 @@ adjacent slots and scope/metadata permutations within a selection without
|
|
|
398
488
|
changing ownership or making them distinct canonical forms. Each selection
|
|
399
489
|
has at most one scope; its metadata blocks retain their authored order.
|
|
400
490
|
|
|
401
|
-
§
|
|
402
|
-
|
|
491
|
+
§lifecycle-slots NOTE accepts no target, scope, or metadata. WAIT retains its
|
|
492
|
+
optional target and ignores syntactically valid scope and metadata without diagnostics
|
|
493
|
+
({§send-wait-scope}). Their literal bodies begin below the header.
|
|
403
494
|
|
|
404
495
|
§heading-inline-body Nonempty body text belongs below the fence header.
|
|
405
496
|
The ingester tolerates body text after horizontal whitespace on the header,
|
|
@@ -413,7 +504,7 @@ routing, timing, or body input. Comments inside a body remain literal except
|
|
|
413
504
|
for the narrowly owned {§misplaced-aside-advisory}.
|
|
414
505
|
|
|
415
506
|
§scheme-metadata-modifier A target may carry one single-line `[metadata]`
|
|
416
|
-
block after its scope;
|
|
507
|
+
block after its scope; executor and SEND fences also admit it without a target.
|
|
417
508
|
Read with its brackets, the block is a JSON array of option objects, merged
|
|
418
509
|
left to right with later keys winning; the keys belong to the selected scheme
|
|
419
510
|
or executor, which owns interpretation, validation and authority. The language
|
|
@@ -422,8 +513,10 @@ balanced brackets inside the block are retained, and double-quoted strings
|
|
|
422
513
|
protect their brackets. Brackets inside `(path)` remain ordinary path and
|
|
423
514
|
glob characters. A block that is not valid JSON, or a second block on one
|
|
424
515
|
operand, is the owner's `400`, never a parser diagnostic. An unfinished block
|
|
425
|
-
or multiline metadata loses its boundary.
|
|
426
|
-
`pattern
|
|
516
|
+
or multiline metadata loses its boundary. Two keys never reach an owner:
|
|
517
|
+
`pattern`, the language's own ({§matcher-option}), and `env`, reserved for the
|
|
518
|
+
service's environment option on the operations that open a process or a
|
|
519
|
+
Worker; the shared reader withholds both from the owner's options.
|
|
427
520
|
|
|
428
521
|
§matcher-option **`pattern` is the matcher, and it lives in the heading.** On
|
|
429
522
|
FIND, READ, KILL, EDIT, and each COPY/MOVE operand, the option
|
|
@@ -453,7 +546,7 @@ whose block left no metadata back bare when the bare form reads back identically
|
|
|
453
546
|
|
|
454
547
|
| Element | Shape or role |
|
|
455
548
|
|---|---|
|
|
456
|
-
| Native OP | `FIND READ EDIT COPY MOVE SEND
|
|
549
|
+
| Native OP | `FIND READ EDIT COPY MOVE SEND BARE WORK FORK KILL NOTE WAIT` |
|
|
457
550
|
| Executor name | Letters, digits, `_`, `.`, `+`, or `-`; reserved OPs win |
|
|
458
551
|
| Fence | Three or more backticks, matched by exact count |
|
|
459
552
|
| `(path)` | Local path, URI, program or tool name; §5 |
|
|
@@ -473,90 +566,68 @@ governed by {§canonical-statement}; runtime conditions remain explicit below.
|
|
|
473
566
|
| EDIT | required file or entry | required for an existing target | literal text |
|
|
474
567
|
| COPY | required source and destination | optional region after each path | empty |
|
|
475
568
|
| MOVE | required source and destination | optional region after each path | empty |
|
|
476
|
-
|
|
|
569
|
+
| execution | the fence name is the runtime; optional program/tool path ({§exec-executor-slot}) | optional timeout, poll | optional program input |
|
|
477
570
|
| BARE | optional prompt resource | none | prompt; optional with a path |
|
|
478
571
|
| WORK | optional fresh `worker://name`, or a prompt resource ({§worker-spawn-prompt-resource}) | none | prompt; optional with a resource |
|
|
479
572
|
| FORK | optional context-inheriting `worker://name`, or a prompt resource | none | prompt; optional with a resource |
|
|
480
573
|
| KILL | required target, including a log item | optional text region ({§kill-scope}) | none; the matcher is the `pattern` option |
|
|
481
|
-
| SEND | optional recipient |
|
|
482
|
-
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
| Inventory condition | Intent | Derived lifecycle status |
|
|
503
|
-
|---|---|---|
|
|
504
|
-
| TASK omitted | Continue silently | 102 |
|
|
505
|
-
| Explicit empty inventory | Recover empty inventory | 102 |
|
|
506
|
-
| Any `in_progress` | Continue independent actionable work | 102 |
|
|
507
|
-
| Any `waiting`, no `in_progress` | Await work or an event | 202 |
|
|
508
|
-
| Any `pending`, no actionable or waiting entry | Review blocked dependencies | 102 |
|
|
509
|
-
| All terminal, any `completed` | End successfully | 200 |
|
|
510
|
-
| All `failed`, nonempty | End unsuccessfully | 499 |
|
|
511
|
-
|
|
512
|
-
`pending` is blocked on another task; `in_progress` can be actively advanced;
|
|
513
|
-
`waiting` awaits an ongoing stream, worker or external event. `completed` is
|
|
514
|
-
successful resolution; `failed` is unsuccessful resolution. A failed sibling
|
|
515
|
-
does not terminate independent unfinished work. The engine does not infer a
|
|
516
|
-
dependency graph from task text.
|
|
517
|
-
|
|
518
|
-
§plan-acp-projection **Only an ACP-facing boundary projects the model-native
|
|
519
|
-
Plan.** It constructs ACP's `{ "entries": [...] }` Plan object from the internal
|
|
520
|
-
array, synthesizes the ACP-required neutral `medium` priority on every entry
|
|
521
|
-
(the model-native Plan carries none). The internal value is never mutated.
|
|
522
|
-
Native `waiting` maps to ACP `in_progress`, with `Waiting:` and a space prepended
|
|
523
|
-
to its display content; native `failed` maps to ACP `completed`, with `Failed:` and a space.
|
|
524
|
-
Both carry their native status in `_meta["plurnk.xyz/status"]`, an edge-owned
|
|
525
|
-
key derived from the native status rather than trusted from authored metadata.
|
|
526
|
-
Other statuses and unrelated metadata remain unchanged. The labels preserve
|
|
527
|
-
meaning even when a generic client ignores extension metadata.
|
|
528
|
-
The projected value validates against the separately owned ACP Plan schema pinned
|
|
529
|
-
to ACP v1
|
|
530
|
-
[`schema-v1.21.0`](https://github.com/agentclientprotocol/agent-client-protocol/tree/schema-v1.21.0)
|
|
531
|
-
commit `272bf799f35a258c6a4107a0410ed361e83683d3`.
|
|
574
|
+
| SEND | optional recipient | recipient-defined; none for workers ({§send-directed-scope}) | message |
|
|
575
|
+
| NOTE | none | none | literal working memory |
|
|
576
|
+
| WAIT | optional event source ({§send-wait-scope}) | ignored | explanation of the wait |
|
|
577
|
+
|
|
578
|
+
§note-value NOTE retains its literal body as ordinary model-owned working memory.
|
|
579
|
+
It has no target, scope, metadata, or lifecycle effect. Its full body participates
|
|
580
|
+
in ordinary log token accounting and model-driven curation; prior notes are not
|
|
581
|
+
automatically hidden. A NOTE-only turn is subject to ordinary conclusion,
|
|
582
|
+
repetition and strike rules.
|
|
583
|
+
|
|
584
|
+
§reasoning-notes NOTE is the only operation admitted from exposed provider
|
|
585
|
+
reasoning. The shared fence parser selects line-leading NOTE statements in a
|
|
586
|
+
quotation-preserving reasoning context: other backtick or tilde code blocks are
|
|
587
|
+
opaque, and operation-heading recovery cannot escape them. Blockquoted and inline
|
|
588
|
+
examples are not headings. Program parsing is unchanged; other reasoned operations
|
|
589
|
+
never execute.
|
|
590
|
+
Selected notes precede the content program in the admitted turn and use the
|
|
591
|
+
ordinary dispatcher, persistence and log projection. Reasoning bytes and content
|
|
592
|
+
bytes remain separate, unchanged forensic sources. Rejected or superseded
|
|
593
|
+
provider attempts cannot commit notes. Non-thinking models use NOTE in their
|
|
594
|
+
ordinary program. No task inventory is inferred from notes or lifecycle prose.
|
|
532
595
|
|
|
533
596
|
§exec-executor-slot The fence name selects the executor directly: for example,
|
|
534
597
|
`python3 (tools/report.py)` or `gitea (issue_list)` on the opening fence line.
|
|
535
|
-
Reserved native OP names take precedence.
|
|
536
|
-
AST
|
|
598
|
+
Reserved native OP names take precedence. Any other name is an executor fence: its
|
|
599
|
+
AST carries the `runtime` tag and no operation keyword, then `target`, metadata, timing and body fields.
|
|
537
600
|
Registration is checked by the runtime, not by the syntax parser. An attached
|
|
538
601
|
MCP service uses that executor path and its owner validates the named tool and
|
|
539
602
|
input-body JSON against its schema. Unknown names do not fall back to a shell.
|
|
540
|
-
|
|
541
|
-
|
|
603
|
+
There is no runtime-less form: every execution names its runtime, and canonical
|
|
604
|
+
shell examples name `sh` explicitly.
|
|
542
605
|
The path names a program or tool and is never split. Metadata such as
|
|
543
606
|
`[{"cwd": "…"}]` remains interpreted by the selected executor.
|
|
544
607
|
|
|
545
|
-
§turn-disposition
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
608
|
+
§turn-disposition WAIT requests parking; its literal body does not control
|
|
609
|
+
scheduling, and its optional target is the label the row keeps, never a join;
|
|
610
|
+
the AST has no independently settable lifecycle status or metadata.
|
|
611
|
+
A turn admits any number of WAITs, all deferred until its other operations
|
|
612
|
+
settle and together one park. End-of-program adjudication owns continuation, joining and completion
|
|
613
|
+
under {§wait-obligation-matrix}; no terminal verb or synthetic receipt is required.
|
|
614
|
+
SEND delivers messages and NOTE retains memory, neither declaring an outcome.
|
|
615
|
+
|
|
616
|
+
§send-wait-scope WAIT's optional target is retained as the row's label; no
|
|
617
|
+
scheme handler runs for it, so every WAIT is the bare park. Scope and metadata
|
|
618
|
+
are discarded without diagnostics,
|
|
619
|
+
including structured scopes. The body, aside, and exact submitted program
|
|
620
|
+
remain intact. WAIT neither creates a schedule nor restricts which ordinary
|
|
621
|
+
events may awaken the loop. A scope slot's content is skipped unread whatever it
|
|
622
|
+
holds (`<sh:///…>` included; #756). Ordinary malformed-header rules still apply;
|
|
623
|
+
a second WAIT is one more label on the same park, never a refusal.
|
|
624
|
+
|
|
625
|
+
§send-directed-scope A recipient SEND carries an optional numeric scope after
|
|
626
|
+
its target and metadata through to the addressed owner, which assigns its
|
|
627
|
+
semantics or refuses it; worker actors refuse one (`scope-unsupported`, 400),
|
|
628
|
+
because later and recurring delivery belong to the schedule family. A
|
|
629
|
+
targetless message takes no scope. A scope never changes the message body or
|
|
630
|
+
disposition.
|
|
560
631
|
|
|
561
632
|
§kill-scope KILL takes an optional text-coordinate scope beside its target, numeric or
|
|
562
633
|
anchored (```` ```KILL (log:///**/READ) <17,-1>``` ```` or
|
|
@@ -575,7 +646,7 @@ and is refused there; a bracket before the target of a non-executor OP is one
|
|
|
575
646
|
bounded header diagnostic that selects nothing.
|
|
576
647
|
|
|
577
648
|
The `<scope>` slot is optional where admitted and its domain is OP-specific. FIND
|
|
578
|
-
scopes ordered results.
|
|
649
|
+
scopes ordered results. Executions and SEND scope owner-defined timing. READ, EDIT, COPY,
|
|
579
650
|
MOVE, and KILL use one universal text algebra independent of mimetype; a log
|
|
580
651
|
KILL admits only its one- and two-line forms for canonical log-body visibility:
|
|
581
652
|
|
|
@@ -621,8 +692,8 @@ parses as `{ kind: "local", raw: "data/users.html", fragment: "readable" }`: the
|
|
|
621
692
|
the path and the rest is the channel (a spelling that opens with `#` names no path and stays
|
|
622
693
|
whole), exactly as `worker:///a.html#readable` decomposes, so
|
|
623
694
|
the `#channel` a READ receipt advertises (`channels: {"#readable": N}`) is addressable in the
|
|
624
|
-
same bare spelling the receipt used
|
|
625
|
-
|
|
695
|
+
same bare spelling the receipt used: a model that appends the channel to the path it was just
|
|
696
|
+
shown addresses the same entry. `raw` is therefore always the path alone; a
|
|
626
697
|
bare path never contains a literal `#`, and `PlurnkParser.stringify` renders the channel back.
|
|
627
698
|
Without a `#` the field is absent, so an older `LocalPath` literal stays valid.
|
|
628
699
|
|
|
@@ -642,9 +713,12 @@ Mutation semantics:
|
|
|
642
713
|
- `<0>` prepends and `<-1>` appends.
|
|
643
714
|
- §empty-mutation-scope Empty mutation content has one writable position: `<0>`, `<1>`, `<-1>`, and `<1,-1>` all insert the body as its complete value. Other scopes resolve against that same empty value through the ordinary coordinate algebra.
|
|
644
715
|
- `<SL,SC,EL,EC>` deletes the exact exclusive-end region and inserts the body at its start.
|
|
645
|
-
- §transfer-resource-selections COPY and MOVE require two singular
|
|
716
|
+
- §transfer-resource-selections COPY and MOVE require two singular
|
|
717
|
+
`ResourceSelection` operands, source first and destination second, and admit
|
|
718
|
+
no body. Each selection binds its own target, scope, matcher, and metadata
|
|
719
|
+
under {§slot-order}, {§matcher-option}, and {§scheme-metadata-modifier}.
|
|
646
720
|
|
|
647
|
-
###
|
|
721
|
+
### Per-operation observations
|
|
648
722
|
|
|
649
723
|
| OP | Successful observation |
|
|
650
724
|
|------|-----------------------------------------------------------------------------------|
|
|
@@ -654,16 +728,16 @@ Mutation semantics:
|
|
|
654
728
|
| COPY | Source and destination selections plus ordered destination effects |
|
|
655
729
|
| MOVE | Source and destination selections plus ordered destination and source effects |
|
|
656
730
|
| SEND | Status and recipient acknowledgement when applicable |
|
|
657
|
-
|
|
|
731
|
+
| execution | Spawn acknowledgement; output arrives through named stream channels |
|
|
658
732
|
| BARE | The one-shot model response |
|
|
659
733
|
| WORK | Spawn acknowledgement; the deliverable arrives through the log |
|
|
660
734
|
| FORK | Spawn acknowledgement; the inherited worker's deliverable arrives through the log |
|
|
661
735
|
| KILL | Status of deletion or termination |
|
|
662
|
-
|
|
|
736
|
+
| NOTE / WAIT | Literal memory or wait explanation |
|
|
663
737
|
|
|
664
738
|
§find-result-unit For FIND, authored target shape fixes the paginated result
|
|
665
739
|
unit. An exact target with a matcher pages flat match locations; a glob or
|
|
666
|
-
folder target, and every
|
|
740
|
+
folder target, and every matcher-less FIND, pages resources. Resolving a glob to
|
|
667
741
|
one resource does not make it exact. The same `<N>`, inclusive `<N,M>`,
|
|
668
742
|
markerless `<1,16>`, and explicit-all `<1,-1>` forms apply to either unit.
|
|
669
743
|
|
|
@@ -676,7 +750,7 @@ EDIT. Whole-channel transfers remain bodyless structural effects; runtime
|
|
|
676
750
|
owners reject binary markers rather than treating a text field as a byte lane.
|
|
677
751
|
|
|
678
752
|
Every operation returns the runtime-neutral `OperationResult` defined by
|
|
679
|
-
{§operation-result}. Its `status` belongs to the result envelope;
|
|
753
|
+
{§operation-result}. Its `status` belongs to the result envelope; a lifecycle operation supplies
|
|
680
754
|
the authored lifecycle intent. Durable operation observations are projected into a later packet;
|
|
681
755
|
retrieval never returns inline within the emitting turn.
|
|
682
756
|
|
|
@@ -733,12 +807,12 @@ never target content. Glob metacharacters remain legal path data.
|
|
|
733
807
|
Matching and folder-scope semantics remain runtime concerns.
|
|
734
808
|
|
|
735
809
|
§worker-name The exported `WORKER_NAME` contract governs names minted for URI
|
|
736
|
-
authority slots:
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
810
|
+
authority slots: `[A-Za-z0-9][A-Za-z0-9_-]{0,62}` (1–63 ASCII characters,
|
|
811
|
+
starting with a letter or digit). Case is preserved and significant;
|
|
812
|
+
`Approach_A` and `approach_a` are distinct names. There is no reserved-name list: the
|
|
813
|
+
runtime's own actor is named `_plurnk`, a spelling the predicate never admits.
|
|
814
|
+
Every matching value, including `self` and `plurnk`, is an ordinary
|
|
815
|
+
literal worker name. This is a minting and registry invariant, not an
|
|
742
816
|
ingestion restriction: the parser decomposes arbitrary URL authorities.
|
|
743
817
|
|
|
744
818
|
## §matcher-prefix-claims 6. Bulk pattern matching
|
|
@@ -754,17 +828,17 @@ matching.
|
|
|
754
828
|
statement-level error the parser discards the rest of that statement and resumes at the
|
|
755
829
|
next heading; the turn shape is decided locally (a turn disposition is recognized by its own
|
|
756
830
|
token, never by a whole-turn alternative), so one malformed heading costs one
|
|
757
|
-
diagnostic and every later statement, the turn disposition included, stands on its own.
|
|
758
|
-
other second path slot names the one-slot rule.
|
|
831
|
+
diagnostic and every later statement, the turn disposition included, stands on its own.
|
|
759
832
|
- §scope-slot-tolerance A line scope written inside a path slot (```` ```COPY (worker:///src.md<2,3>) ````)
|
|
760
833
|
is read as `(worker:///src.md) <2,3>` — `<` and `>` are not URI characters, so a `<…>` right
|
|
761
834
|
before a slot's closing paren can only be a scope; every path slot of a statement is repaired
|
|
762
835
|
the same way — and the slip is one warning-severity advisory at the `<`, placed right after its
|
|
763
836
|
statement, stating the `(path) <scope>` form that was used. The statement runs; a warning is
|
|
764
837
|
never a strike. A `<` anywhere else in the slot remains the lexer's refusal.
|
|
765
|
-
- §
|
|
766
|
-
error at
|
|
767
|
-
|
|
838
|
+
- §extra-path-slot A path slot beyond the operation's admitted operands is a parser
|
|
839
|
+
error at its opening paren. Report the unexpected slot and the grammar's expected
|
|
840
|
+
alternatives when available, without inferring pattern intent or imposing another
|
|
841
|
+
operation's operand count. The statement is dropped and its siblings run.
|
|
768
842
|
|
|
769
843
|
| Prefix | Dialect | Canonical form | Typed admission | Runtime owner |
|
|
770
844
|
|-----------|----------|--------------------------------------|-----------------------------------|---------------------|
|
|
@@ -816,9 +890,9 @@ The operation column names the canonical AST operation after
|
|
|
816
890
|
| COPY/MOVE source | 0/1/2/4 text coordinates | Region copied or moved from the selected source |
|
|
817
891
|
| COPY/MOVE destination | 0/1/2/4 text coordinates after target | Region replaced or insertion point at the destination |
|
|
818
892
|
| KILL | 0/1/2 text coordinates | Whole target when absent; one physical line or inclusive range when present ({§kill-scope}) |
|
|
819
|
-
|
|
|
820
|
-
|
|
|
821
|
-
| Directed SEND | Owner-defined numeric scope |
|
|
893
|
+
| execution | `timeout[,poll]` | Spawn lifetime bound and poll cadence in minutes |
|
|
894
|
+
| WAIT | None | Scope is ignored ({§send-wait-scope}) |
|
|
895
|
+
| Directed SEND | Owner-defined numeric scope | Carried to the addressed owner; worker actors refuse it ({§send-directed-scope}) |
|
|
822
896
|
|
|
823
897
|
Text coordinates use the algebra in {§text-scope-semantics}: one integer is a
|
|
824
898
|
whole line, two integers are an inclusive whole-line range, and four integers
|
|
@@ -834,8 +908,7 @@ its `L`, `SL`, or `EL` position denotes a line. Columns, prepend `0`, and append
|
|
|
834
908
|
`-1` remain numeric. Exact READ, EDIT, COPY/MOVE source and destination,
|
|
835
909
|
KILL, and client LOOK preserve these positions in `TextLineMarker`; core resolves them
|
|
836
910
|
against the addressed current text before operation-specific numeric scope
|
|
837
|
-
semantics run.
|
|
838
|
-
result positions remain numeric and reject anchors. Numeric text scopes remain
|
|
911
|
+
semantics run. FIND's result positions remain numeric and reject anchors. Numeric text scopes remain
|
|
839
912
|
canonical and fully supported. Parser acceptance does not imply model-facing
|
|
840
913
|
recommendation.
|
|
841
914
|
|
|
@@ -870,56 +943,49 @@ npm test
|
|
|
870
943
|
````
|
|
871
944
|
`````
|
|
872
945
|
|
|
873
|
-
The inner shell example is EDIT content, not an
|
|
946
|
+
The inner shell example is EDIT content, not an execution. The same
|
|
874
947
|
rule protects code examples in SEND, WORK, FORK, BARE and every other body.
|
|
875
948
|
|
|
876
949
|
## 9. Turn dispositions
|
|
877
950
|
|
|
878
|
-
|
|
879
|
-
({§
|
|
880
|
-
|
|
951
|
+
The runtime adjudicates a nonempty admitted program against actual messages,
|
|
952
|
+
results and live obligations ({§wait-obligation-matrix}). A response with no
|
|
953
|
+
operation receives empty-turn recovery, not successful completion ({§empty-turn}).
|
|
881
954
|
|
|
882
955
|
| Intent | Nominal status | Meaning |
|
|
883
956
|
|---|---|---|
|
|
884
|
-
|
|
|
885
|
-
|
|
|
886
|
-
|
|
|
887
|
-
|
|
|
888
|
-
|
|
|
957
|
+
| Unanswered messages or unobserved results | 102 | Continue silently |
|
|
958
|
+
| WAIT | 202 | Park when a live obligation exists; otherwise continue at 102 |
|
|
959
|
+
| All messages answered, live work remains | 202 | Join the held work |
|
|
960
|
+
| All messages answered, results observed, no held work | 200 | The admitted program concludes; no repeated response is required |
|
|
961
|
+
| KILL own worker | 499 | Cancel unfinished work in that worker and its descendants |
|
|
889
962
|
| Runtime or infrastructure failure | 5xx | Not a model-authored task status |
|
|
890
963
|
|
|
891
|
-
###
|
|
964
|
+
### The terminal contract (waitpid)
|
|
892
965
|
|
|
893
|
-
The model may supply one
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
obligations (spawned children, open streams, pending results); the grammar
|
|
897
|
-
polices *shape* only. Asking
|
|
898
|
-
the human is the native `question` EXEC tool ({§question-tool}), not a
|
|
966
|
+
The model may supply one WAIT per turn. The host, not the grammar, owns
|
|
967
|
+
turn boundaries and adjudicates the loop's actual obligations. Asking
|
|
968
|
+
the human is the native `question` executor tool ({§question-tool}), not a
|
|
899
969
|
disposition. The shape rules ARE structural:
|
|
900
970
|
|
|
901
|
-
- §send-mid-reservation
|
|
902
|
-
A turn admits
|
|
903
|
-
({§disposition-anywhere}); the runtime executes
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
(operator, 2026-09-12: models state the plan first; the inventory is a
|
|
907
|
-
statement about state, not a boundary). `PlurnkParser.parse` admits every
|
|
971
|
+
- §send-mid-reservation WAIT is reserved ({§turn-disposition}).
|
|
972
|
+
A turn admits any number of lifecycle declarations, anywhere among its
|
|
973
|
+
operations ({§disposition-anywhere}); the runtime executes them last, as one park.
|
|
974
|
+
- §disposition-anywhere A disposition may sit anywhere in a model turn
|
|
975
|
+
without imposing a program boundary. `PlurnkParser.parse` admits every
|
|
908
976
|
operation before and after it in authored order; the runtime defers only the
|
|
909
|
-
|
|
977
|
+
dispositions until the other admitted operations settle
|
|
910
978
|
({§op-execution-order}). Nothing is dropped and no diagnostic is raised for
|
|
911
|
-
position.
|
|
979
|
+
position. Omission does not synthesize a disposition ({§turn-shape}).
|
|
912
980
|
- SEND is communication: an optional recipient path and an optional body.
|
|
913
|
-
- §park-202-only
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
- §inventory-only-turn A TASK-only turn is valid for every inventory intent.
|
|
919
|
-
Actionable work does not require an invented OP and does not imply parking.
|
|
981
|
+
- §park-202-only WAIT joins live work: an open stream or a live
|
|
982
|
+
child. With none, it continues. It takes no scope ({§send-wait-scope});
|
|
983
|
+
a future message is scheduled through the schedule family.
|
|
984
|
+
- §lifecycle-only-turn A WAIT-, SEND-, or NOTE-only turn is valid.
|
|
985
|
+
NOTE does not request parking or acknowledge messages.
|
|
920
986
|
Ordinary repetition, strike and execution limits still apply.
|
|
921
987
|
|
|
922
|
-
SEND with no `(path)`
|
|
988
|
+
SEND with no `(path)` answers the open messages without ending the turn. SEND with
|
|
923
989
|
`(path)` directs the message to that recipient. Neither changes loop status.
|
|
924
990
|
|
|
925
991
|
### §send-body SEND body projection
|
|
@@ -932,17 +998,22 @@ defines no synthetic scheme or READ-back convention for them.
|
|
|
932
998
|
|
|
933
999
|
## §parser-architecture 10. Parser architecture
|
|
934
1000
|
|
|
1001
|
+
The implementation this section describes lives in `@plurnk/plurnk-parser`
|
|
1002
|
+
({§parser-consumers}); this section remains the contract it implements.
|
|
1003
|
+
|
|
935
1004
|
ANTLR owns framing, slots and statement composition; AstBuilder produces the
|
|
936
1005
|
schema-owned AST. Registration, effects and authority remain runtime concerns.
|
|
937
1006
|
|
|
938
1007
|
```mermaid
|
|
939
1008
|
stateDiagram-v2
|
|
940
1009
|
[*] --> DEFAULT
|
|
1010
|
+
DEFAULT --> QUOTATION: a fence that opens no operation
|
|
1011
|
+
QUOTATION --> DEFAULT: its matching closer
|
|
941
1012
|
DEFAULT --> SLOTS: fenced native OP or executor
|
|
942
1013
|
SLOTS --> TARGET: (
|
|
943
1014
|
TARGET --> SLOTS: )
|
|
944
|
-
SLOTS --> METADATA:
|
|
945
|
-
METADATA --> SLOTS:
|
|
1015
|
+
SLOTS --> METADATA: [
|
|
1016
|
+
METADATA --> SLOTS: ]
|
|
946
1017
|
SLOTS --> BODY: header newline or tolerated inline body
|
|
947
1018
|
SLOTS --> DEFAULT: matching compact closer
|
|
948
1019
|
BODY --> DEFAULT: matching standalone closer, no nested block
|
|
@@ -960,13 +1031,13 @@ already ends in one. Interstatement whitespace belongs to no body.
|
|
|
960
1031
|
A header starts at column zero; the first operation may follow provider preamble
|
|
961
1032
|
without a separating newline. Text outside operation blocks is ignored in every
|
|
962
1033
|
parser tier: before, between, and after operations. It produces no AST item,
|
|
963
|
-
message, receipt, or diagnostic. Exact source remains in `ops
|
|
1034
|
+
message, receipt, or diagnostic. Exact source remains in `ops://<worker>/` under
|
|
964
1035
|
{§turn-ops-log-curation}; body bytes and source positions are unchanged. A matching
|
|
965
1036
|
closer still ends its body, and no missing closer is inferred. No generic Markdown
|
|
966
1037
|
rendering, indentation stripping or recursive code-block extraction occurs.
|
|
967
1038
|
Only a header aside has aside semantics.
|
|
968
1039
|
|
|
969
|
-
##
|
|
1040
|
+
## 12. Public API
|
|
970
1041
|
|
|
971
1042
|
The package root is the single JavaScript and TypeScript entry point. Shared AST
|
|
972
1043
|
and wire types come from generated schemas; the small hand-maintained parser
|
|
@@ -977,26 +1048,23 @@ express. Consumers never receive ANTLR parse-tree or token types.
|
|
|
977
1048
|
operation is reported by one hard diagnostic (`no valid Plurnk operation was
|
|
978
1049
|
found.`), which the host may admit as an empty turn rather than reject
|
|
979
1050
|
(plurnk-core `§empty-turn`). An explicit disposition may sit anywhere in it
|
|
980
|
-
({§disposition-anywhere}).
|
|
981
|
-
means silent continuation: no synthesized statement, diagnostic, receipt,
|
|
1051
|
+
({§disposition-anywhere}). An omitted WAIT produces no synthesized statement, diagnostic, receipt,
|
|
982
1052
|
warning, or strike. The authored operations and source remain unchanged.
|
|
983
|
-
Explicit empty or malformed inventories retain their own handling.
|
|
984
1053
|
Unfinished blocks never receive inferred closers.
|
|
985
|
-
Bounded operation errors retain valid siblings
|
|
986
|
-
|
|
1054
|
+
Bounded operation errors retain valid siblings, and so does a lost boundary:
|
|
1055
|
+
the statements that closed before `unparsedTail.from` are facts, and only what
|
|
1056
|
+
follows is undefined ({§unparsed-tail-boundary}).
|
|
987
1057
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
the executable blocks themselves are the program.
|
|
1058
|
+
The host records programs per turn; no operation acts as a separator between
|
|
1059
|
+
saved programs. There is no outer Markdown program wrapper; the executable
|
|
1060
|
+
blocks themselves are the program.
|
|
992
1061
|
|
|
993
1062
|
§tier-entrypoints Each parser entry point owns one document tier:
|
|
994
1063
|
|
|
995
1064
|
| Entry point | Accepted document | Result statement type |
|
|
996
1065
|
|--------------------------------|----------------------------------------------------------------|-----------------------|
|
|
997
|
-
| `PlurnkParser.parse` | One operation-bearing model turn; at most one
|
|
1066
|
+
| `PlurnkParser.parse` | One operation-bearing model turn; at most one lifecycle declaration, anywhere | `PlurnkStatement` |
|
|
998
1067
|
| `PlurnkParser.parseStatements` | Zero or more protocol statements | `PlurnkStatement` |
|
|
999
|
-
| `PlurnkParser.parseLog` | One or more consecutive disposition-ended turns | `PlurnkStatement` |
|
|
1000
1068
|
| `PlurnkParser.parseClient` | Executable blocks, including the read-shaped LOOK command | `ClientStatement` |
|
|
1001
1069
|
|
|
1002
1070
|
Every entry point ignores outside text under {§whitespace-contract} and returns
|
|
@@ -1004,26 +1072,28 @@ ordered `statement` and `error` items. When present, {§unparsed-tail-boundary}
|
|
|
1004
1072
|
extent. The statement `op` field discriminates the generated per-operation
|
|
1005
1073
|
union.
|
|
1006
1074
|
|
|
1007
|
-
§root-value-api The package-root runtime namespace is closed
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
|
1013
|
-
|
|
1014
|
-
| `
|
|
1015
|
-
| `
|
|
1016
|
-
| `
|
|
1017
|
-
| `
|
|
1018
|
-
| `
|
|
1019
|
-
| `
|
|
1020
|
-
| `
|
|
1021
|
-
| `
|
|
1022
|
-
| `
|
|
1023
|
-
| `
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1075
|
+
§root-value-api The package-root runtime namespace is closed. Its exact membership has one home,
|
|
1076
|
+
`src/index.test.ts`, which fails on any addition or removal; the table names the families and
|
|
1077
|
+
their owners. All other root exports are TypeScript types. `PlurnkParser` and `parsePath` are not
|
|
1078
|
+
among them: the parser is `@plurnk/plurnk-parser`'s ({§parser-consumers}).
|
|
1079
|
+
|
|
1080
|
+
| Root value(s) | Consumer contract | Exact owner |
|
|
1081
|
+
|-----------------------------------------------------|---------------------------------------------------------------------|-------------------------------------------|
|
|
1082
|
+
| `Validator` and one `Invalid…Error` per assertion | Validation and typed failure against the owning JSON Schemas | {§wire-entrypoint} |
|
|
1083
|
+
| `Problems` | RFC 9457 Problem construction and model projection | {§problem-details}, {§problem-projection} |
|
|
1084
|
+
| `PlurnkParseError` | JSON-serializable positioned parser diagnostic | {§parse-diagnostics} |
|
|
1085
|
+
| `PathSyntax` | Target-slot spelling and exact-versus-glob classification | {§path-parentheses}, {§path-glob} |
|
|
1086
|
+
| `TurnDisposition` | The one turn disposition and its recognition | {§turn-disposition} |
|
|
1087
|
+
| `CapabilityAdmission` | Admission of a capability descriptor against policy layers | {§capability-admission} |
|
|
1088
|
+
| `PLURNK_OPS`, `INTERNAL_ROW_OPS`, `PLURNK_FENCE` | The closed operation alphabet and the language's fence | {§canonical-statement} |
|
|
1089
|
+
| `PROPOSAL_POLICIES` | The vocabulary a loop policy chooses from | {§loop-policy} |
|
|
1090
|
+
| `WORKER_NAME` | Authority minting predicate | {§worker-name} |
|
|
1091
|
+
| `UNKNOWN_POSITION` | Frozen sentinel for an AST statement without retained parsed source | {§parser-position} |
|
|
1092
|
+
|
|
1093
|
+
The remaining values are small pure helpers over those contracts (`isExecution`, `writtenOp`,
|
|
1094
|
+
`lifecycleOfLoopStatus`, `selectWorkerLoop`, `renderJsonResult`, `formatJsonDocument`,
|
|
1095
|
+
`aguiConformanceReport`) and the closed name patterns and vocabularies (`RUNTIME_TAG`,
|
|
1096
|
+
`SKILL_NAME`, `REASONING_POLICIES`).
|
|
1027
1097
|
|
|
1028
1098
|
§parser-construction-boundary Parser construction components are internal rather
|
|
1029
1099
|
than alternate consumer entry points:
|
|
@@ -1033,20 +1103,10 @@ than alternate consumer entry points:
|
|
|
1033
1103
|
| `AstBuilder` | Consumes generated ANTLR contexts; `PlurnkParser` and `parsePath` own its API |
|
|
1034
1104
|
| `PlurnkErrorStrategy`, `RecordingListener` | Assemble parser recovery and diagnostics around `antlr4ng`; consumers receive `PlurnkParseError` values |
|
|
1035
1105
|
|
|
1036
|
-
### CLI
|
|
1037
|
-
|
|
1038
|
-
```text
|
|
1039
|
-
plurnk-contracts [file] parse a file, or standard input when omitted
|
|
1040
|
-
plurnk-contracts --help show usage
|
|
1041
|
-
```
|
|
1042
|
-
|
|
1043
|
-
The CLI prints the parse result as JSON. It exits `0` when no error item or
|
|
1044
|
-
`unparsedTail` exists and `1` otherwise.
|
|
1045
|
-
|
|
1046
1106
|
## 13. Runtime-neutral wire contracts
|
|
1047
1107
|
|
|
1048
1108
|
§wire-entrypoint The package root exports generated wire types, `Problems`, and
|
|
1049
|
-
`Validator` alongside the
|
|
1109
|
+
`Validator` alongside the AST types. Their owning JSON Schemas are published
|
|
1050
1110
|
through `@plurnk/plurnk-contracts/schema/*.json`, not re-exported as root values.
|
|
1051
1111
|
|
|
1052
1112
|
### §text-region 13.1 Text regions
|
|
@@ -1164,6 +1224,19 @@ Internal invariant violations throw and preserve their cause. An external
|
|
|
1164
1224
|
protocol may require its own error envelope; its adapter maps that envelope to
|
|
1165
1225
|
or from the canonical Problem without creating another PLURNK failure contract.
|
|
1166
1226
|
|
|
1227
|
+
§problem-error-carrier `Problems.fromError(error)` recognizes existing failure
|
|
1228
|
+
carriers without depending on a producer's exception class:
|
|
1229
|
+
|
|
1230
|
+
| Carrier | Interpretation |
|
|
1231
|
+
|---------|----------------|
|
|
1232
|
+
| `error.result` present | Validate the complete {§operation-result}; return its Problem, if any |
|
|
1233
|
+
| Otherwise, `error.problem` present | Validate and return {§problem-details} unchanged |
|
|
1234
|
+
| Absent or malformed carrier | Return `null`; the caller retains the original exception as an unexpected failure |
|
|
1235
|
+
|
|
1236
|
+
Recognition never derives recovery text from an exception message, changes its
|
|
1237
|
+
status, or rescues a malformed result through a second Problem field. Unexpected
|
|
1238
|
+
accessor or validator exceptions propagate.
|
|
1239
|
+
|
|
1167
1240
|
§problem-projection `ProblemProjection` is the sole compact model-packet view of
|
|
1168
1241
|
an exact `ProblemDetails`. `Problems.project(problem, context)` validates both
|
|
1169
1242
|
representations and rejects a status that contradicts the enclosing row.
|
|
@@ -1225,22 +1298,23 @@ client ID plus symbolic secret, or neither for server-advertised Dynamic Client
|
|
|
1225
1298
|
Registration fallback. A definition cannot combine those identity modes.
|
|
1226
1299
|
|
|
1227
1300
|
§mcp-configuration-overlay `McpConfigurationOverlay` is the bounded raw
|
|
1228
|
-
configuration projection a client may carry to MCP list and enable actions
|
|
1229
|
-
|
|
1230
|
-
|
|
1301
|
+
configuration projection a client may carry to MCP list and enable actions: its
|
|
1302
|
+
string-valued `PLURNK_MCP_*` variables, whole. Which of those names are the
|
|
1303
|
+
host's own controls is the host's fact alone — its parser skips every control
|
|
1304
|
+
it owns, so a carried timeout or enabled list has no effect and no client or
|
|
1305
|
+
contract restates that vocabulary.
|
|
1231
1306
|
The client does not interpret this map. The MCP host composes it over the
|
|
1232
1307
|
lower normalized definition through the same parser that admits service
|
|
1233
1308
|
environment declarations, then validates the resulting
|
|
1234
1309
|
`McpServerDefinition`. Carrying the overlay does not connect, persist, or
|
|
1235
1310
|
expand credentials by itself.
|
|
1236
1311
|
|
|
1237
|
-
`SkillDefinition` is the one definition the
|
|
1238
|
-
family accepts and persists: the standard
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
truth about installation.
|
|
1312
|
+
`SkillDefinition` is the one definition the workspace `skills` Functionality
|
|
1313
|
+
family accepts and persists: the standard `name`, source `scope`, and optional
|
|
1314
|
+
installer `source`. `Validator.assertSkillDefinition` validates the wire shape;
|
|
1315
|
+
the schema's name grammar is exposed as `SKILL_NAME` for loaders and discovery
|
|
1316
|
+
({§agent-skills-name}). Core owns installation truth and lifecycle
|
|
1317
|
+
({§skills-functionality}).
|
|
1244
1318
|
|
|
1245
1319
|
`A2aAgentDefinition` is the one definition the Worker `a2a` Functionality
|
|
1246
1320
|
family accepts and persists: the local alias `name` (the `a2a://<name>`
|
|
@@ -1264,11 +1338,22 @@ interaction, and event owners through this port.
|
|
|
1264
1338
|
from user-authored prompt content. An adapter may expose no public means to set
|
|
1265
1339
|
it; Core validates and records it through the same prompt admission path.
|
|
1266
1340
|
|
|
1341
|
+
`runLoop.attachments` carries typed bytes selected by the adapter;
|
|
1342
|
+
`runLoop.envelope` retains opaque protocol evidence under
|
|
1343
|
+
{§message-envelope-evidence}. `readMessages` projects durable inbox messages
|
|
1344
|
+
and successful conversation replies independently of log visibility, retaining
|
|
1345
|
+
each reply's `answers` addresses (empty for incoming messages).
|
|
1346
|
+
`resolveClientInteraction` may carry the accepted answer's message evidence;
|
|
1347
|
+
Core validates the resolution, retains the arrival, then resumes the operation.
|
|
1348
|
+
|
|
1267
1349
|
§application-worker-observation Worker observation exposes durable identity,
|
|
1268
1350
|
origin, immediate parent identity, minted `kind` (`conversation`; `fork` for a
|
|
1269
1351
|
child carrying a fork boundary; `work` for any other child), and `lifecycle`,
|
|
1270
|
-
the worker's
|
|
1271
|
-
when it has none).
|
|
1352
|
+
the worker's representative work loop projected through {§loop-lifecycle-vocabulary} (`idle`
|
|
1353
|
+
when it has none). `selectWorkerLoop` chooses running before parked before queued;
|
|
1354
|
+
ties select the oldest unresolved sequence. With no live work, the latest terminal
|
|
1355
|
+
settlement wins (sequence breaks equal timestamps). Newer terminal history never
|
|
1356
|
+
hides unfinished work. Maintenance-only loops do not change this projection;
|
|
1272
1357
|
their ordinary turns and results remain durable history. `readWorker` resolves exactly one id or name and returns
|
|
1273
1358
|
`null` when absent. `listWorkers` filters collections by origin or lineage
|
|
1274
1359
|
position; an omitted parent filter means every position and an explicit `null`
|
|
@@ -1286,9 +1371,7 @@ in `@plurnk/plurnk-contracts` is that projection's one owner.
|
|
|
1286
1371
|
§application-loop-observation Loop observation exposes the durable scheduler
|
|
1287
1372
|
state of work loops (excluding maintenance-only administrative loops), exact terminal `OperationResult`, and exact count of packet-bearing
|
|
1288
1373
|
Turns for one owned Worker. Packetless producer Turns and physical provider
|
|
1289
|
-
retries do not contribute to `packetCount`.
|
|
1290
|
-
(ISO date), optional `intervalMinutes`, and `recurrenceId` (the original task id).
|
|
1291
|
-
Packet notifications carry the same timing; ordinary tasks omit it. Exterior
|
|
1374
|
+
retries do not contribute to `packetCount`. Exterior
|
|
1292
1375
|
adapters consume this projection instead of reconstructing lifecycle from
|
|
1293
1376
|
events or persistence; events remain the live notification edge.
|
|
1294
1377
|
|
|
@@ -1307,7 +1390,6 @@ class PlurnkParseError extends Error {
|
|
|
1307
1390
|
readonly column: number;
|
|
1308
1391
|
readonly source: ErrorSource;
|
|
1309
1392
|
readonly severity: Severity;
|
|
1310
|
-
readonly code?: "invalid-turn-structure";
|
|
1311
1393
|
}
|
|
1312
1394
|
```
|
|
1313
1395
|
|
|
@@ -1345,10 +1427,8 @@ and 3.30.2](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html).
|
|
|
1345
1427
|
the sole and complete owner of syntax-error messaging because it holds the
|
|
1346
1428
|
parse state, lexer mode, and expected-token set that no consumer has. It
|
|
1347
1429
|
produces the final diagnostic message, deduplicated expected-token lists, and
|
|
1348
|
-
turn-shape diagnostics ({§turn-shape}).
|
|
1349
|
-
neither does the position of a present one ({§disposition-anywhere}).
|
|
1350
|
-
document boundary carries `code: "invalid-turn-structure"`, which cannot be
|
|
1351
|
-
recovered as an individual failed operation. Source with no
|
|
1430
|
+
turn-shape diagnostics ({§turn-shape}). An omitted lifecycle declaration produces no diagnostic, and
|
|
1431
|
+
neither does the position of a present one ({§disposition-anywhere}). Source with no
|
|
1352
1432
|
parsed operation yields `no valid Plurnk operation was found.` Targeted
|
|
1353
1433
|
diagnostics are:
|
|
1354
1434
|
|
|
@@ -1358,9 +1438,7 @@ diagnostics are:
|
|
|
1358
1438
|
its flags (`/(?i)shutdown|reactor/` is `/shutdown|reactor/i`; `^(?i)note:` is the
|
|
1359
1439
|
anchored regex with `i`), with one warning-severity advisory naming the flag
|
|
1360
1440
|
position after the closing `/`. Only a leading group of `i`, `m` and `s` lifts;
|
|
1361
|
-
`(?i:…)` scoped modifiers are valid ECMAScript and pass through untouched.
|
|
1362
|
-
the 2026-09-13 dumbox demo pass, where the model wrote the inline form, was
|
|
1363
|
-
refused, and rewrote it as a trailing flag one turn later.
|
|
1441
|
+
`(?i:…)` scoped modifiers are valid ECMAScript and pass through untouched.
|
|
1364
1442
|
- §regex-trailing-text A valid `/pattern/flags` prefix followed by horizontal
|
|
1365
1443
|
whitespace and trailing text receives one concise trailing-content
|
|
1366
1444
|
diagnostic, with or without flags, without assuming what the extra text was
|
|
@@ -1371,7 +1449,9 @@ diagnostics are:
|
|
|
1371
1449
|
matcher, in whichever dialect its first characters claim
|
|
1372
1450
|
({§matcher-prefix-claims}): `/re/i`, `^anchored`, `//xpath`, `$.json`, `~words`,
|
|
1373
1451
|
`&symbol`, or a sigil-less glob or literal such as `TODO` or `*.ts`. Those
|
|
1374
|
-
|
|
1452
|
+
matchers remain independent of owner options: a block without `pattern` never
|
|
1453
|
+
erases the heading matcher, and invalid blocks still reach the owning validator.
|
|
1454
|
+
These operations take no body, so heading-line text can mean nothing else. On EDIT only
|
|
1375
1455
|
a sigil lifts, because plain heading-line text is the replacement body it always
|
|
1376
1456
|
was; the lines beneath the heading are then the replacement, and none deletes each
|
|
1377
1457
|
match ({§edit-pattern}). A trailing `<!-- aside -->` on the same line stays the
|
|
@@ -1381,8 +1461,7 @@ diagnostics are:
|
|
|
1381
1461
|
`FIND (src/parser.ts) /\bparse\w+\b/` is the same operation as
|
|
1382
1462
|
`FIND (src/parser.ts) [{"pattern": "/\\bparse\\w+\\b/"}]`. `^` claims the regex
|
|
1383
1463
|
dialect without slashes or flags: the whole text is the pattern, so
|
|
1384
|
-
`READ (
|
|
1385
|
-
2026-09-12: "Recursive Reasoning").
|
|
1464
|
+
`READ (notes.md) ^Decision:.*` selects lines beginning with `Decision:`.
|
|
1386
1465
|
- §trailing-slots **Slots after the matcher peel off the right.** The heading text after
|
|
1387
1466
|
the matcher is read backwards: a trailing `<!-- aside -->`, a trailing `<scope>` in the
|
|
1388
1467
|
shapes the lexer admits (result positions on FIND, text coordinates elsewhere) and a
|
|
@@ -1390,9 +1469,8 @@ diagnostics are:
|
|
|
1390
1469
|
any order, each taken once and only when the heading did not already carry that slot,
|
|
1391
1470
|
until what remains is the matcher. `READ (a.rs) /fn resolve_/ <1,-1> <!-- entities -->`
|
|
1392
1471
|
is the same operation as `READ (a.rs) <1,-1> /fn resolve_/ <!-- entities -->`, with
|
|
1393
|
-
one warning-severity advisory naming the canonical order for the scope or block
|
|
1394
|
-
|
|
1395
|
-
2026-09-13 dumbox run refused three headings for this in one turn). A matcher that
|
|
1472
|
+
one warning-severity advisory naming the canonical order for the scope or block:
|
|
1473
|
+
the grammar swallows up anything that passes as legitimate plurnk. A matcher that
|
|
1396
1474
|
itself ends in one of those shapes takes the option escape.
|
|
1397
1475
|
- §matcher-body-redirect **A body beneath those headings.** Text below the heading
|
|
1398
1476
|
of a FIND, READ or KILL is a body, and those operations take none: the builder
|
|
@@ -1413,7 +1491,7 @@ diagnostics are:
|
|
|
1413
1491
|
- §invalid-scope-diagnostic **Malformed scope content.** After a properly spaced
|
|
1414
1492
|
scope opener, report the offending scope (at most 64 code points, ending at
|
|
1415
1493
|
`>` or the heading's line end) and its operation's constraint: FIND result
|
|
1416
|
-
positions,
|
|
1494
|
+
positions, execution minutes, text coordinates, or no scope. Do not append advice for
|
|
1417
1495
|
other operations or infer why the producer supplied the value. Spacing and
|
|
1418
1496
|
boundary-loss diagnostics retain their own contracts.
|
|
1419
1497
|
- §misplaced-aside-advisory **Aside in the body.** A READ or FIND whose
|
|
@@ -1427,7 +1505,10 @@ diagnostics are:
|
|
|
1427
1505
|
({§matcher-body-redirect}).
|
|
1428
1506
|
|
|
1429
1507
|
§error-shape The diagnostic class determines how much guidance the parser may
|
|
1430
|
-
provide
|
|
1508
|
+
provide. Advisories belong to one successfully built statement. A rejected
|
|
1509
|
+
statement emits its hard diagnostic, not normalization advisories; neither a
|
|
1510
|
+
rejection nor an internal exception carries advisories into another statement
|
|
1511
|
+
or parser invocation.
|
|
1431
1512
|
|
|
1432
1513
|
| Class | Surface | Message contract |
|
|
1433
1514
|
|------------------------|-----------------------|-------------------------------------------------------------------------------------------|
|
|
@@ -1449,7 +1530,7 @@ Examples of canonical hard facts:
|
|
|
1449
1530
|
- `unrecognized character '<' in target`
|
|
1450
1531
|
- `unexpected bracket modifier; the fence name selects the executor`
|
|
1451
1532
|
- `unrecognized character 'X' in statement header`
|
|
1452
|
-
- `
|
|
1533
|
+
- `WAIT's body begins below the header`
|
|
1453
1534
|
- `expected ')'; got ':'`
|
|
1454
1535
|
|
|
1455
1536
|
Each malformed statement produces at most one hard error. The first recorded
|
|
@@ -1466,7 +1547,9 @@ without a closer is not such a case: it ends under {§closer-fallback}. `ParseRe
|
|
|
1466
1547
|
before that point; recovered contexts and diagnostics at or beyond it are not
|
|
1467
1548
|
public results. The tail is one separate boundary fact, not an additional
|
|
1468
1549
|
malformed-statement diagnostic. Consumers must treat anything from that point
|
|
1469
|
-
onward as undefined and must never dispatch a recovered statement from it
|
|
1550
|
+
onward as undefined and must never dispatch a recovered statement from it; the
|
|
1551
|
+
facts before it are ordinary facts, and a consumer that runs them owes the
|
|
1552
|
+
author the tail's reason.
|
|
1470
1553
|
|
|
1471
1554
|
| Consumer duty | Contract |
|
|
1472
1555
|
|--------------------|----------------------------------------------------------------------------------------------------------------|
|
|
@@ -1485,6 +1568,6 @@ runtime constructs this; the parser provides the fields):
|
|
|
1485
1568
|
"column": 12,
|
|
1486
1569
|
"source": "parser",
|
|
1487
1570
|
"severity": "error",
|
|
1488
|
-
"message": "READ block opened at line 1 but was not closed with
|
|
1571
|
+
"message": "READ block opened at line 1 but was not closed with 4 backticks"
|
|
1489
1572
|
}
|
|
1490
1573
|
```
|