@plurnk/plurnk-contracts 1.4.0 → 1.6.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/README.md +10 -6
- package/SPEC.md +368 -231
- package/dist/plurnk.gemma.gbnf +160 -0
- package/dist/plurnk.qwen.gbnf +149 -0
- package/dist/schema/ClientStatement.json +7 -1
- package/dist/schema/EntryReadResult.json +1 -9
- package/dist/schema/MatcherBody.json +1 -1
- package/dist/schema/OperationResult.json +3 -0
- package/dist/schema/PlurnkStatement.json +57 -12
- package/dist/schema/ProposalProjection.json +1 -1
- package/dist/schema/ProviderAccounting.json +30 -0
- package/dist/schema/ProviderCost.json +6 -15
- package/dist/schema/ProviderRequestAccounting.json +17 -0
- package/dist/schema/ProviderUsage.json +40 -0
- package/dist/schema/RangeExtent.json +47 -0
- package/dist/schema/ResourceSelection.json +1 -1
- package/dist/schema/TextLineMarker.json +21 -0
- package/dist/src/AstBuilder.d.ts.map +1 -1
- package/dist/src/AstBuilder.js +123 -22
- package/dist/src/AstBuilder.js.map +1 -1
- package/dist/src/JsonResult.d.ts +3 -0
- package/dist/src/JsonResult.d.ts.map +1 -0
- package/dist/src/JsonResult.js +37 -0
- package/dist/src/JsonResult.js.map +1 -0
- package/dist/src/PlurnkErrorStrategy.d.ts +1 -0
- package/dist/src/PlurnkErrorStrategy.d.ts.map +1 -1
- package/dist/src/PlurnkErrorStrategy.js +42 -19
- package/dist/src/PlurnkErrorStrategy.js.map +1 -1
- package/dist/src/PlurnkParser.d.ts.map +1 -1
- package/dist/src/PlurnkParser.js +22 -139
- package/dist/src/PlurnkParser.js.map +1 -1
- package/dist/src/TagSignal.d.ts +15 -0
- package/dist/src/TagSignal.d.ts.map +1 -0
- package/dist/src/TagSignal.js +48 -0
- package/dist/src/TagSignal.js.map +1 -0
- package/dist/src/Validator.d.ts +6 -1
- package/dist/src/Validator.d.ts.map +1 -1
- package/dist/src/Validator.js +36 -1
- package/dist/src/Validator.js.map +1 -1
- package/dist/src/generated/plurnkLexer.d.ts +99 -54
- package/dist/src/generated/plurnkLexer.d.ts.map +1 -1
- package/dist/src/generated/plurnkLexer.js +889 -498
- package/dist/src/generated/plurnkLexer.js.map +1 -1
- package/dist/src/generated/plurnkParser.d.ts +99 -108
- package/dist/src/generated/plurnkParser.d.ts.map +1 -1
- package/dist/src/generated/plurnkParser.js +943 -1068
- package/dist/src/generated/plurnkParser.js.map +1 -1
- package/dist/src/generated/plurnkParserVisitor.d.ts +19 -5
- package/dist/src/generated/plurnkParserVisitor.d.ts.map +1 -1
- package/dist/src/generated/plurnkParserVisitor.js +16 -4
- package/dist/src/generated/plurnkParserVisitor.js.map +1 -1
- package/dist/src/index.d.ts +6 -2
- 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 +2 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.generated.d.ts +98 -24
- package/dist/src/types.generated.d.ts.map +1 -1
- package/dist/src/types.js +4 -1
- package/dist/src/types.js.map +1 -1
- package/package.json +8 -8
- package/plurnk.md +143 -133
- package/dist/plurnk.gbnf +0 -394
package/SPEC.md
CHANGED
|
@@ -8,18 +8,26 @@ is the single code API for those contracts.
|
|
|
8
8
|
|
|
9
9
|
| Surface | Canonical export or artifact |
|
|
10
10
|
| ------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
11
|
-
| Parser, AST, validators, Problems, results, Notices, text regions
|
|
11
|
+
| Parser, AST, validators, Problems, results, Notices, text regions and extents | `@plurnk/plurnk-contracts` |
|
|
12
12
|
| Effective loop policy and its default | `LoopFlags`, `DEFAULT_LOOP_FLAGS` |
|
|
13
13
|
| Stopped-world client contract | `ProposalDisposition`, `ProposalProjection` |
|
|
14
14
|
| Client capability presentation | `ClientDisplayCapabilities` |
|
|
15
15
|
| JSON Schemas | `@plurnk/plurnk-contracts/schema/*.json` |
|
|
16
|
-
|
|
|
16
|
+
| Generated JSON result rendering | `renderJsonResult` |
|
|
17
|
+
| Local-model rails | `@plurnk/plurnk-contracts/plurnk.{gemma,qwen}.gbnf` |
|
|
17
18
|
| Model language reference | `plurnk.md` in the package |
|
|
18
19
|
|
|
19
20
|
§contract-representations JSON Schema is authoritative for shared data shapes. TypeScript types are
|
|
20
21
|
generated from the schemas; ANTLR is authoritative for accepted model-language
|
|
21
22
|
syntax; GBNF remains the bounded generation aid described in §1.2.
|
|
22
23
|
|
|
24
|
+
§json-result-rendering `renderJsonResult` is the one presentation serializer
|
|
25
|
+
for generated JSON operation results. A top-level array remains one valid,
|
|
26
|
+
compact JSON value but places each item on its own physical line by adding only
|
|
27
|
+
item-boundary newlines; an empty or single-item array and every non-array value
|
|
28
|
+
remain one line. It never rewrites arbitrary stored JSON, whose original lines
|
|
29
|
+
remain source coordinates.
|
|
30
|
+
|
|
23
31
|
## §contract-layers 1.1 Contract layers and admission boundary
|
|
24
32
|
|
|
25
33
|
PLURNK uses one contract with deliberately different projections. A tolerant
|
|
@@ -30,7 +38,7 @@ semantics valid.
|
|
|
30
38
|
```mermaid
|
|
31
39
|
flowchart LR
|
|
32
40
|
canon["Canonical model teaching<br/>plurnk.md"]
|
|
33
|
-
rail["Optional raw generation rail<br/>
|
|
41
|
+
rail["Optional raw generation rail<br/>Gemma or Qwen template profile"]
|
|
34
42
|
free["Other admitted input"]
|
|
35
43
|
syntax["ANTLR lexer + parser<br/>syntax and document tier"]
|
|
36
44
|
ast["AstBuilder<br/>typed, serializable AST"]
|
|
@@ -47,8 +55,8 @@ flowchart LR
|
|
|
47
55
|
|--------------------------|-------------------------------------|---------------------------------------------------------------------------------|
|
|
48
56
|
| Stable current law | `SPEC.md` | Owns invariants and boundaries; forge issues retain history |
|
|
49
57
|
| Canonical model teaching | `plurnk.md` | Teaches the lean spelling and operational model the model should emit |
|
|
50
|
-
| Constrained generation | generated `plurnk
|
|
51
|
-
| Accepted syntax | `plurnkLexer.g4`, `plurnkParser.g4` | Recognizes document tiers,
|
|
58
|
+
| Constrained generation | generated `plurnk.*.gbnf` | Increases likely ANTLR compliance without reproducing all parser/runtime checks |
|
|
59
|
+
| Accepted syntax | `plurnkLexer.g4`, `plurnkParser.g4` | Recognizes document tiers, heading lanes, slot shape, and section boundaries |
|
|
52
60
|
| Typed admission | `AstBuilder` | Produces JSON-serializable unions and validates deterministic body/path syntax |
|
|
53
61
|
| Shared wire data | `schema/*.json` | Defines runtime-neutral data shapes projected into generated TypeScript |
|
|
54
62
|
| Stateful behavior | consuming runtime | Resolves addresses, permissions, selection arithmetic, effects, and lifecycle |
|
|
@@ -72,17 +80,43 @@ The schemas own the runtime-neutral shapes; core owns their stateful values.
|
|
|
72
80
|
| `LoopFlags` | Complete effective `mode`, `auto`, `noWeb`, `noInteraction`, and `noProposals` | Validate/expand persisted partial policy before use |
|
|
73
81
|
| `ProposalDisposition` | Client authority, or the loop's exact automatic accept/reject | Compute precedence from effective loop policy, proposal kind, and stale-target truth |
|
|
74
82
|
| `ProposalProjection` | Identity, review target/body/attrs, effective flags, stale signal, disposition | Derive one validated projection for live delivery and durable reconnect discovery |
|
|
75
|
-
| `
|
|
83
|
+
| `ProviderUsage` | Conventional input/output totals with cache and reasoning details | Preserve observed quantities without replacing absence with zero |
|
|
84
|
+
| `ProviderCost` | Exact charged, estimated, or unknown monetary evidence | Normalize one monetary disposition for each physical provider request |
|
|
85
|
+
| `ProviderRequestAccounting` | Usage and cost evidence for one physical provider request | Preserve request order across retries, failover, success, and failure |
|
|
86
|
+
| `ProviderAccounting` | Ordered requests plus deterministic usage and exact-USD projections | Derive loop, protocol, telemetry, and client reporting without a second authority |
|
|
76
87
|
|
|
77
88
|
`DEFAULT_LOOP_FLAGS` is the contracts-owned effective default value. A consumer may persist a partial object as an implementation detail, but it never exposes or acts on that partial representation as though it were the complete contract.
|
|
78
89
|
|
|
79
|
-
§provider-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
zero
|
|
90
|
+
§provider-usage `ProviderUsage` records only known non-negative safe-integer
|
|
91
|
+
quantities. `inputTokens` includes every input category; cache reads and cache
|
|
92
|
+
writes are details within it. `outputTokens` includes reasoning; text and
|
|
93
|
+
reasoning are details within it. `totalTokens` equals input plus output whenever
|
|
94
|
+
all three are present. A detail is no greater than its containing total, and a
|
|
95
|
+
complete detail partition sums to that total. An omitted field is unknown; an
|
|
96
|
+
explicit zero is provider evidence or an exact derivation from complete known
|
|
97
|
+
components. Consumers never estimate a token category from text length.
|
|
98
|
+
|
|
99
|
+
§provider-cost `ProviderCost` represents one physical provider request's
|
|
100
|
+
monetary disposition. `charged` preserves a provider-reported canonical decimal
|
|
101
|
+
amount and currency, with an optional decimal USD equivalent for a non-USD
|
|
102
|
+
charge. `estimated` preserves a calculated decimal amount and currency.
|
|
103
|
+
`unknown` requires a reason. Zero is an ordinary exact amount under `charged`
|
|
104
|
+
or `estimated`; there is no separate free mechanism. Decimal strings preserve
|
|
105
|
+
evidence without binary floating-point rewriting. Unknown is not zero.
|
|
106
|
+
|
|
107
|
+
§provider-request-accounting `ProviderRequestAccounting` is the indivisible
|
|
108
|
+
accounting fact for one issued physical request. Its provider, model, outcome,
|
|
109
|
+
optional protocol status, optional {§provider-usage}, and required
|
|
110
|
+
{§provider-cost} travel together. Ordered request records preserve retries and
|
|
111
|
+
capacity failover; a later response never replaces an earlier request.
|
|
112
|
+
|
|
113
|
+
§provider-accounting `ProviderAccounting.requests` is the source evidence.
|
|
114
|
+
`usage` and `costUsd` are deterministic projections of that ordered set, not
|
|
115
|
+
independent inputs. Each usage field is present only when every contributing
|
|
116
|
+
request has that field known; the empty set totals to explicit zero. `costUsd`
|
|
117
|
+
is the exact decimal sum only when every request is expressible in USD and is
|
|
118
|
+
`null` otherwise. Consumers do not recompute provider rates or convert
|
|
119
|
+
currencies while reading the projection.
|
|
86
120
|
|
|
87
121
|
The parser returns ordered statement, error, and text items. It recovers at a
|
|
88
122
|
trustworthy statement boundary when possible and sets `unparsedTail` when a
|
|
@@ -92,110 +126,152 @@ and parse diagnostics are separate contracts.
|
|
|
92
126
|
## 1.2 GBNF Generation Rail
|
|
93
127
|
|
|
94
128
|
§gbnf-rail-purpose ANTLR and AstBuilder define accepted PLURNK input. The generated
|
|
95
|
-
`dist/plurnk.gbnf`
|
|
129
|
+
`dist/plurnk.{gemma,qwen}.gbnf` are optional local llama.cpp sampling rails kept lean
|
|
96
130
|
to make useful, ANTLR-compliant turns more likely without reproducing every
|
|
97
131
|
parser or semantic validator. Parse compatibility is a design goal balanced
|
|
98
132
|
against rail size and sampling efficiency, not a language-subset guarantee. A
|
|
99
133
|
rail-legal operation can therefore produce a parser or AstBuilder error; consumers
|
|
100
134
|
apply their ordinary admission and bounded-operation recovery contract.
|
|
135
|
+
The complete package build emits both rails; they are not source-controlled. Source and
|
|
136
|
+
differential tests serialize the owning generator directly, while installation
|
|
137
|
+
coverage verifies the packed export.
|
|
101
138
|
|
|
102
139
|
|
|
103
|
-
The
|
|
140
|
+
The rails share one turn shape but begin at their respective sampled-token
|
|
141
|
+
boundaries:
|
|
104
142
|
|
|
105
143
|
```ebnf
|
|
106
|
-
root-
|
|
144
|
+
root-gemma ::= channel sep framed-turn
|
|
145
|
+
root-qwen ::= think-body think-close sep framed-turn
|
|
146
|
+
root-qwen-response ::= think-open root-qwen
|
|
147
|
+
framed-turn ::= turn | fence-open turn fence-close
|
|
148
|
+
turn ::= plan sep tail-0
|
|
107
149
|
```
|
|
108
150
|
|
|
109
|
-
§gbnf-turn-shape `
|
|
110
|
-
`<|channel>thought\n
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
151
|
+
§gbnf-turn-shape The `gemma` transport root samples one complete
|
|
152
|
+
`<|channel>thought\n … <channel|>` enclosure. A Qwen-style chat template has
|
|
153
|
+
already supplied `<think>\n` when the `qwen` transport root begins, so that root
|
|
154
|
+
samples the body and required `</think>` closer. Each generated artifact declares
|
|
155
|
+
an `@plurnk-response-root`; for `qwen`, that root composes the template opener
|
|
156
|
+
back onto the sampled text so the complete pre-projection response can be graded.
|
|
157
|
+
Either body may be empty and cannot contain its profile's opener or closer.
|
|
158
|
+
`sep` is zero through seven whitespace characters. The projected PLURNK content
|
|
159
|
+
is either bare or enclosed once in a paired `plurnk` Markdown fence; the turn
|
|
160
|
+
begins with `# PLAN0`, and every following operation is a same-lane `## OP0`
|
|
161
|
+
section.
|
|
162
|
+
`tail-0` admits zero through fourteen internal operations followed by exactly
|
|
163
|
+
one terminal SEND under the existing terminal-eligibility rules.
|
|
116
164
|
|
|
117
165
|
```mermaid
|
|
118
166
|
flowchart LR
|
|
119
|
-
|
|
167
|
+
sampled["Constrained sampled text<br/>profile reasoning bytes · sep · optional fence · PLAN0 turn"]
|
|
168
|
+
raw["Pre-projection response<br/>one complete reasoning envelope · PLURNK turn"]
|
|
120
169
|
split["llama.cpp<br/>reasoning_format: auto"]
|
|
121
|
-
reasoning["reasoning_content<br/>
|
|
122
|
-
content["content<br/>PLAN through terminal SEND"]
|
|
170
|
+
reasoning["reasoning_content<br/>envelope body"]
|
|
171
|
+
content["content<br/>bare or fenced PLAN through terminal SEND"]
|
|
123
172
|
parser["ANTLR + AstBuilder<br/>admission and diagnostics"]
|
|
173
|
+
sampled --> raw
|
|
124
174
|
raw --> split
|
|
125
175
|
split --> reasoning
|
|
126
176
|
split --> content
|
|
127
177
|
content --> parser
|
|
128
178
|
```
|
|
129
179
|
|
|
130
|
-
§gbnf-reasoning-boundary GBNF applies
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
180
|
+
§gbnf-reasoning-boundary GBNF applies from sampled token zero before response
|
|
181
|
+
projection. The declared response root composes any template-provided prefix for
|
|
182
|
+
independent validation of the pre-projection evidence. The two projected fields
|
|
183
|
+
are not separate GBNF languages, and `content` alone is not revalidated as though
|
|
184
|
+
it still contained the required reasoning envelope. Provider and core own the
|
|
185
|
+
projection evidence and rail-verdict boundary; this package owns the sampled and
|
|
186
|
+
response roots plus the parser/AstBuilder result.
|
|
187
|
+
|
|
188
|
+
§rail-heading-boundaries On the GBNF rail, PLAN and every operation use lane `0`.
|
|
189
|
+
Every reserved PLAN or operation heading stem is structural, regardless of the
|
|
190
|
+
suffix a model attempts next, so a non-`0` pseudo-heading cannot be swallowed as
|
|
191
|
+
literal body text. Rail bodies therefore cannot quote reserved headings from any
|
|
192
|
+
lane. This makes both the canonical suffix and section boundary structurally
|
|
193
|
+
available during constrained generation; ANTLR remains the wider language and
|
|
194
|
+
accepts intentional alternate-lane literals during ingestion.
|
|
195
|
+
|
|
196
|
+
§gbnf-curation-shaping The rail admits OPEN/FOLD curation terms, a canonical
|
|
197
|
+
`log:` target, and a matcher independently. It accepts any ordered mixture of
|
|
198
|
+
unsigned, `+`, and `-` terms without proving that the combination selects a log
|
|
199
|
+
item; ANTLR and AstBuilder own that condition, while runtime owns wider ingested
|
|
200
|
+
target resolution.
|
|
140
201
|
|
|
141
202
|
## §canonical-statement 2. Canonical statement form
|
|
142
203
|
|
|
143
204
|
```text
|
|
144
|
-
|
|
145
|
-
|
|
205
|
+
# PLANsuffix
|
|
206
|
+
body
|
|
146
207
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
body retains both delimiters: `::OPsuffix`.
|
|
208
|
+
## OPsuffix [signal]? (path)? <scope>?
|
|
209
|
+
body?
|
|
210
|
+
```
|
|
151
211
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
212
|
+
§section-boundary A statement is one Markdown section. PLAN alone uses a level-one
|
|
213
|
+
heading; every other operation uses a level-two heading. Its body is the
|
|
214
|
+
character-perfect section content before the next structural heading or EOF.
|
|
215
|
+
Canonical adjacent sections have one blank separator line. That final separator
|
|
216
|
+
line is syntax and is not body content; any additional preceding blank lines
|
|
217
|
+
remain body content. The tolerant ingester also admits a structural heading on
|
|
218
|
+
the immediately following line.
|
|
219
|
+
|
|
220
|
+
§empty-section An empty section has no body lines between its heading and the
|
|
221
|
+
section separator (or EOF) and normalizes to a null body.
|
|
222
|
+
|
|
223
|
+
| Element | Canonical contract |
|
|
224
|
+
|--------------|---------------------------------------------------------------------------|
|
|
225
|
+
| `# PLAN` | Required level-one turn anchor |
|
|
226
|
+
| `## OP` | Level-two protocol operation |
|
|
227
|
+
| `suffix` | Heading lane, joined directly to PLAN or OP |
|
|
228
|
+
| `[signal]` | Optional operation-specific signal, preceded by one space |
|
|
229
|
+
| `(path)` | Optional target slot, preceded by one space |
|
|
230
|
+
| `<scope>` | Optional numeric scope, preceded by one space |
|
|
231
|
+
| line ending | Ends the single-line heading |
|
|
232
|
+
| `body` | Zero or more characters of operation-specific, character-perfect content |
|
|
233
|
+
| blank line | Canonical section separator; excluded from the preceding body |
|
|
163
234
|
|
|
164
235
|
The following constraints are structural:
|
|
165
236
|
|
|
166
|
-
- §
|
|
237
|
+
- §lane-match PLAN establishes one lane for the turn. A heading is structural
|
|
238
|
+
only when its suffix character-matches that lane; a different suffix remains
|
|
239
|
+
ordinary body text.
|
|
240
|
+
- PLAN is the only H1 operation and every non-PLAN operation is H2.
|
|
241
|
+
- A header occupies one physical line.
|
|
167
242
|
- Each admitted signal, target, and scope slot appears at most once.
|
|
168
|
-
- OPEN, FOLD, WORK, FORK, and KILL do not admit a scope slot.
|
|
169
|
-
-
|
|
243
|
+
- OPEN, FOLD, BARE, WORK, FORK, and KILL do not admit a scope slot.
|
|
244
|
+
- An ingested suffix is `[A-Za-z0-9_]*`; canonical teaching and the GBNF use `0`.
|
|
170
245
|
|
|
171
246
|
§slot-order Canonical producers and the GBNF rail emit signal, then target, then
|
|
172
|
-
scope
|
|
173
|
-
|
|
174
|
-
|
|
247
|
+
scope, with one ASCII space before every present slot. Slot delimiters make
|
|
248
|
+
their boundaries unambiguous, so the tolerant ANTLR ingester accepts zero or
|
|
249
|
+
more horizontal whitespace characters before each slot and any permutation of
|
|
250
|
+
the slots admitted by that operation, at most once each. Accepted spacing and
|
|
251
|
+
permutation are not second canonical spellings.
|
|
175
252
|
|
|
176
253
|
The ingester also accepts several bounded noncanonical forms so it can explain
|
|
177
254
|
or safely execute understandable input:
|
|
178
255
|
|
|
179
|
-
| Tolerated input
|
|
180
|
-
|
|
181
|
-
| Reordered admitted slots
|
|
256
|
+
| Tolerated input | Canonical or runtime disposition |
|
|
257
|
+
|---------------------------------------------------|---------------------------------------------------------------------|
|
|
258
|
+
| Reordered admitted slots | Producers retain signal → target → scope order |
|
|
182
259
|
| Missing target on a generally targeted operation | AST carries `null`; the runtime rejects when the target is required |
|
|
183
|
-
| PLAN modifiers or
|
|
184
|
-
| KILL annotation body
|
|
185
|
-
| Dash-separated or comma-space scope numbers
|
|
186
|
-
|
|
|
260
|
+
| PLAN modifiers or a non-`0` lane | Model canon keeps PLAN slotless and uses lane `0` |
|
|
261
|
+
| KILL annotation body | AST preserves it; model teaching leaves the KILL section empty |
|
|
262
|
+
| Dash-separated or comma-space scope numbers | Producers use adjacent comma-separated numbers |
|
|
263
|
+
| Empty content where semantics require a body | The empty section normalizes null; the operation owner rejects it |
|
|
187
264
|
|
|
188
265
|
## 3. Lexical elements
|
|
189
266
|
|
|
190
267
|
| Element | Accepted shape or role |
|
|
191
268
|
|-------------|--------------------------------------------------------------------|
|
|
192
|
-
| `OP` | `FIND READ EDIT COPY MOVE OPEN FOLD SEND EXEC WORK FORK KILL PLAN` |
|
|
193
|
-
| `suffix` | `[A-Za-z0-9_]*`, adjacent to
|
|
269
|
+
| `OP` | `FIND READ EDIT COPY MOVE OPEN FOLD SEND EXEC BARE WORK FORK KILL PLAN` |
|
|
270
|
+
| `suffix` | `[A-Za-z0-9_]*`, adjacent to PLAN or OP |
|
|
194
271
|
| `[signal]` | Operation-specific tags, identifier, branch, or integer |
|
|
195
272
|
| `(path)` | Local path or scheme URL target; detailed in §5 |
|
|
196
273
|
| `<scope>` | One or more signed integers or decimals; detailed in §7 |
|
|
197
|
-
| `body` | Opaque text
|
|
198
|
-
| `:OPsuffix` | Adjacent colon plus the exact opening operation and suffix |
|
|
274
|
+
| `body` | Opaque section text before the next same-lane heading or EOF |
|
|
199
275
|
|
|
200
276
|
## §op-shapes 4. Per-operation semantics
|
|
201
277
|
|
|
@@ -205,14 +281,15 @@ governed by {§canonical-statement}; runtime conditions remain explicit below.
|
|
|
205
281
|
| OP | `[signal]` | `(path)` | `<scope>` | `body` |
|
|
206
282
|
|------|-------------------------------|----------------------------------------------|---------------------------------|--------------------------------|
|
|
207
283
|
| PLAN | none | none | none | required intended goals |
|
|
208
|
-
| FIND | optional
|
|
209
|
-
| READ | optional
|
|
210
|
-
| EDIT | optional
|
|
211
|
-
| COPY | optional
|
|
212
|
-
| MOVE | optional
|
|
213
|
-
| FOLD | optional
|
|
214
|
-
| OPEN | optional filter tags
|
|
284
|
+
| FIND | optional add log tags | required target or glob | optional result range | optional matcher |
|
|
285
|
+
| READ | optional add log tags | required target | optional text region | empty |
|
|
286
|
+
| EDIT | optional add log tags | required file or entry | required for an existing target | literal text |
|
|
287
|
+
| COPY | optional add log tags | required source | optional source region | required destination selection |
|
|
288
|
+
| MOVE | optional add log tags | required source | optional source region | required destination selection |
|
|
289
|
+
| FOLD | optional filter/change tags | optional log selection | none | optional matcher |
|
|
290
|
+
| OPEN | optional filter/change tags | optional log selection | none | optional matcher |
|
|
215
291
|
| EXEC | optional executor | optional local working path | optional timeout, poll | optional executor input |
|
|
292
|
+
| BARE | optional add log tags | none | none | required prompt |
|
|
216
293
|
| WORK | optional Git branch | required fresh `worker://name` | none | required prompt |
|
|
217
294
|
| FORK | optional Git branch | required context-inheriting `worker://name` | none | required prompt |
|
|
218
295
|
| KILL | optional target-specific code | required target, including a log item | none | empty |
|
|
@@ -224,15 +301,19 @@ Directed SEND and KILL delegate any present code to the addressed target's
|
|
|
224
301
|
operation contract; a live process may interpret a KILL code as a Unix signal,
|
|
225
302
|
but that interpretation does not define KILL generally.
|
|
226
303
|
|
|
227
|
-
§plan-intended-goals **PLAN records
|
|
228
|
-
|
|
304
|
+
§plan-intended-goals **PLAN records working-state deltas.** Its concise body adds
|
|
305
|
+
new material conclusions or unresolved questions and the current turn's priorities;
|
|
306
|
+
it does not restate settled context. PLAN is public, durable log content—not provider
|
|
229
307
|
reasoning. Dispatch records it and has no other runtime effect.
|
|
230
308
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
309
|
+
§log-tag-signal FIND, READ, EDIT, COPY, MOVE, and BARE canonically express additions
|
|
310
|
+
as `+tag`. Because those operations have no tag-selection semantics, ANTLR also
|
|
311
|
+
tolerates unsigned `tag` as an equivalent addition; `-tag` is invalid. Core
|
|
312
|
+
strips any `+`; the signal neither filters nor modifies resources. OPEN and
|
|
313
|
+
FOLD treat every unsigned `tag` as an ALL-tags selector, then add each `+tag`
|
|
314
|
+
and remove each `-tag` from the selected log items. Signed terms never select,
|
|
315
|
+
so either a target, matcher, or unsigned tag is required. Adding and removing
|
|
316
|
+
the same tag conflicts. Neither curation operation exposes a positional scope.
|
|
236
317
|
|
|
237
318
|
The `<scope>` slot is optional where admitted and its domain is OP-specific. FIND
|
|
238
319
|
scopes ordered results. EXEC and SEND scope timing. READ, EDIT, COPY, and
|
|
@@ -248,20 +329,34 @@ MOVE use one universal text algebra independent of mimetype:
|
|
|
248
329
|
two-integer line selections normalize to the same exclusive-end `TextRegion`
|
|
249
330
|
used by four-coordinate selections. Whole-line replacement deliberately
|
|
250
331
|
accounts for newline separators; it is an ergonomic projection over exact
|
|
251
|
-
replacement, not a different mimetype navigation mode.
|
|
332
|
+
replacement, not a different mimetype navigation mode. An end bound beyond
|
|
333
|
+
the available content clamps to the final addressable endpoint; the start bound
|
|
334
|
+
must resolve. As an unadvertised
|
|
252
335
|
ingestion tolerance, the runtime accepts three integers as
|
|
253
336
|
`startLine,startColumn,endLine` and immediately normalizes them to the complete
|
|
254
337
|
four-coordinate region ending after the final code point of `endLine`.
|
|
255
338
|
Producers never emit that form. Other arities and decimal text coordinates are
|
|
256
339
|
runtime 416 failures.
|
|
257
340
|
|
|
258
|
-
|
|
259
|
-
complete
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
341
|
+
§bare-statement **BARE requests one isolated model inference.** Its required
|
|
342
|
+
body is the complete prompt. It admits only optional additive log tags: no
|
|
343
|
+
target, scope, persistent worker identity, or output-language statement shape
|
|
344
|
+
is represented in the AST. Runtime provider selection, batching, accounting,
|
|
345
|
+
and observation timing belong to the consuming service.
|
|
346
|
+
|
|
347
|
+
§read-find-normalization An authored READ with a nonempty matcher body or a
|
|
348
|
+
target path classified as a glob normalizes during AST construction to one
|
|
349
|
+
ordinary FIND statement. Target, signals, scope, and matcher are preserved;
|
|
350
|
+
FIND's result pagination and projection contract then applies. The canonical
|
|
351
|
+
AST retains no parallel matcher-READ mode, and the runtime performs no READ
|
|
352
|
+
fan-out.
|
|
353
|
+
|
|
354
|
+
§read-exact-target After normalization, READ targets one exact resource (a
|
|
355
|
+
local path or scheme URL, with optional `#channel` fragment or
|
|
356
|
+
`{header: value}` metadata) and has no matcher body. A `<scope>` on READ selects
|
|
357
|
+
a text region from that exact target. Without a scope, READ defaults to
|
|
358
|
+
`<1,16>`; `<1,-1>` explicitly selects all text. Decimal scope components are
|
|
359
|
+
invalid on READ.
|
|
265
360
|
|
|
266
361
|
Mutation semantics:
|
|
267
362
|
|
|
@@ -271,13 +366,13 @@ Mutation semantics:
|
|
|
271
366
|
- An empty body deletes the selected text.
|
|
272
367
|
- `<0>` prepends and `<-1>` appends.
|
|
273
368
|
- `<SL,SC,EL,EC>` deletes the exact exclusive-end region and inserts the body at its start.
|
|
274
|
-
- COPY and MOVE parse the body as a destination `ResourceSelection`: a target plus an optional destination scope. Header target, fragment, and scope independently select the source resource, channel, and region.
|
|
369
|
+
- §destination-scope-boundary COPY and MOVE parse the body as a destination `ResourceSelection`: a target plus an optional destination scope. A destination scope is final body content; a scope-shaped suffix followed by residue before the section boundary is rejected rather than reinterpreted as target data. Scope-shaped text elsewhere remains target data, and a URL requiring the reserved terminal spelling percent-encodes its angle brackets. Header target, fragment, and scope independently select the source resource, channel, and region.
|
|
275
370
|
|
|
276
371
|
### §operation-observation Per-operation observations
|
|
277
372
|
|
|
278
373
|
| OP | Successful observation |
|
|
279
374
|
|------|-----------------------------------------------------------------------------------|
|
|
280
|
-
| FIND |
|
|
375
|
+
| FIND | Resource catalog groups or exact-target match locations |
|
|
281
376
|
| READ | Complete or scoped body projections plus optional text match evidence |
|
|
282
377
|
| EDIT | Status plus a bounded receipt for the effect that landed |
|
|
283
378
|
| COPY | Source and destination selections plus ordered destination effects |
|
|
@@ -286,11 +381,18 @@ Mutation semantics:
|
|
|
286
381
|
| FOLD | Status and matched log-item count |
|
|
287
382
|
| SEND | Status and recipient acknowledgement when applicable |
|
|
288
383
|
| EXEC | Spawn acknowledgement; output arrives through named stream channels |
|
|
384
|
+
| BARE | The one-shot model response |
|
|
289
385
|
| WORK | Spawn acknowledgement; the deliverable arrives through the log |
|
|
290
386
|
| FORK | Spawn acknowledgement; the inherited worker's deliverable arrives through the log |
|
|
291
387
|
| KILL | Status of deletion or termination |
|
|
292
388
|
| PLAN | Status of durable intended-goals logging |
|
|
293
389
|
|
|
390
|
+
§find-result-unit For FIND, authored target shape fixes the paginated result
|
|
391
|
+
unit. An exact target with a matcher pages flat match locations; a glob or
|
|
392
|
+
folder target, and every body-less FIND, pages resources. Resolving a glob to
|
|
393
|
+
one resource does not make it exact. The same `<N>`, inclusive `<N,M>`,
|
|
394
|
+
markerless `<1,16>`, and explicit-all `<1,-1>` forms apply to either unit.
|
|
395
|
+
|
|
294
396
|
§copy-move-observation COPY and MOVE log projections preserve both admitted operand selections,
|
|
295
397
|
including their independent scopes, whether the result changed state, was a
|
|
296
398
|
304 no-op, or failed after admission. Operands identify the request; `effects`
|
|
@@ -346,7 +448,7 @@ pairs such as `\*` retain both characters for glob interpretation. Encoding
|
|
|
346
448
|
escapes backslashes before parentheses, so every target string round-trips.
|
|
347
449
|
Pathname producers retain the deliberate `%28`/`%29` alias and `%3C` spelling,
|
|
348
450
|
but must use the lexical layer for identity-bearing query and fragment text
|
|
349
|
-
rather than changing their percent-encoded spelling. Newlines and
|
|
451
|
+
rather than changing their percent-encoded spelling. Newlines and raw `<` are
|
|
350
452
|
never target content. Glob metacharacters remain legal path data.
|
|
351
453
|
|
|
352
454
|
§path-glob `PathSyntax` owns exact-path versus path-pattern classification.
|
|
@@ -378,8 +480,10 @@ ingestion restriction: the parser decomposes arbitrary URL authorities.
|
|
|
378
480
|
|
|
379
481
|
## §matcher-prefix-claims 6. Bulk pattern matching
|
|
380
482
|
|
|
381
|
-
FIND,
|
|
382
|
-
the body opaquely; AstBuilder assigns the dialect from its leading
|
|
483
|
+
FIND, OPEN, FOLD, and authored READ accept an optional body matcher. The lexer
|
|
484
|
+
preserves the body opaquely; AstBuilder assigns the dialect from its leading
|
|
485
|
+
characters, then normalizes matcher-bearing READ to FIND under
|
|
486
|
+
{§read-find-normalization}.
|
|
383
487
|
A leading prefix claims its dialect. Invalid claimed syntax is a positioned
|
|
384
488
|
visitor error and never falls back to glob matching.
|
|
385
489
|
|
|
@@ -405,7 +509,9 @@ statements remain recoverable when their boundaries are trustworthy.
|
|
|
405
509
|
|
|
406
510
|
- §pattern-body-single-line The GBNF rail permits only single-line matcher
|
|
407
511
|
bodies. A regex that matches a newline uses the two-character `\n` escape.
|
|
408
|
-
ANTLR
|
|
512
|
+
ANTLR preserves the complete section body; the same-lane heading boundary
|
|
513
|
+
keeps every following statement independently parseable without a matcher-
|
|
514
|
+
specific implicit close rule.
|
|
409
515
|
- §pattern-body-leading-colon The GBNF rail forbids `:` as the first matcher
|
|
410
516
|
character. Empty matchers and later colons remain valid; a regex such as
|
|
411
517
|
`/^:needle/` expresses a pattern beginning with a literal colon.
|
|
@@ -413,31 +519,47 @@ statements remain recoverable when their boundaries are trustworthy.
|
|
|
413
519
|
## §scope-slot 7. Scope markers
|
|
414
520
|
|
|
415
521
|
The model-facing slot is `<scope>`; the AST field remains the historical
|
|
416
|
-
`lineMarker
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
|
424
|
-
|
|
425
|
-
|
|
|
426
|
-
|
|
|
427
|
-
|
|
|
522
|
+
`lineMarker`. Numeric scopes preserve ordered components in `LineMarker`;
|
|
523
|
+
text-coordinate operations use `TextLineMarker`, whose line positions may also
|
|
524
|
+
carry rendered anchors. The operation owner assigns every component's role.
|
|
525
|
+
|
|
526
|
+
The operation column names the canonical AST operation after
|
|
527
|
+
{§read-find-normalization}.
|
|
528
|
+
|
|
529
|
+
| Operation | Canonical components | Meaning |
|
|
530
|
+
|-----------------------|----------------------------------------|----------------------------------------------------------------------------|
|
|
531
|
+
| FIND | optional threshold, then 0–2 positions | Inclusive resource or exact-target location positions ({§find-result-unit}; defaults to `<1,16>`) |
|
|
532
|
+
| READ / client LOOK | 0/1/2/4 text coordinates | Text projection from one exact selected file, entry, or log item |
|
|
533
|
+
| EDIT | 0/1/2/4 text coordinates | Text replacement, deletion, prepend, or append |
|
|
534
|
+
| COPY/MOVE source | 0/1/2/4 text coordinates | Region copied or moved from the selected source |
|
|
535
|
+
| COPY/MOVE destination | 0/1/2/4 text coordinates after target | Region replaced or insertion point at the destination |
|
|
536
|
+
| EXEC | `timeout[,poll]` | Spawn lifetime bound and poll cadence in seconds |
|
|
537
|
+
| Terminal SEND `[202]` | `timeout[,poll]` | Bounded or indefinite wait and optional poll cadence |
|
|
428
538
|
|
|
429
539
|
Text coordinates use the algebra in {§text-scope-semantics}: one integer is a
|
|
430
540
|
whole line, two integers are an inclusive whole-line range, and four integers
|
|
431
541
|
are an exact start-inclusive/end-exclusive region. Mutation scopes additionally
|
|
432
|
-
admit `0` as prepend and `-1` as append. A leading decimal on semantic FIND
|
|
433
|
-
|
|
434
|
-
|
|
542
|
+
admit `0` as prepend and `-1` as append. A leading decimal on semantic FIND
|
|
543
|
+
is a similarity threshold; any remaining integers select result positions. READ
|
|
544
|
+
does not admit decimal scope components.
|
|
545
|
+
|
|
546
|
+
§text-line-anchor-syntax A text coordinate admits a case-sensitive line anchor
|
|
547
|
+
spelled `@` followed by exactly five Base62 characters (`0-9A-Za-z`) wherever
|
|
548
|
+
its `L`, `SL`, or `EL` position denotes a line. Columns, prepend `0`, and append
|
|
549
|
+
`-1` remain numeric. Exact READ, EDIT, COPY/MOVE source and destination, and
|
|
550
|
+
client LOOK preserve these positions in `TextLineMarker`; core resolves them
|
|
551
|
+
against the addressed current text before operation-specific numeric scope
|
|
552
|
+
semantics run. A matcher-bearing or path-glob READ normalizes to FIND, whose
|
|
553
|
+
result positions remain numeric and reject anchors. Numeric text scopes remain
|
|
554
|
+
canonical and fully supported. Parser acceptance does not imply model-facing
|
|
555
|
+
recommendation.
|
|
435
556
|
|
|
436
557
|
§scope-marker-forms Canonical producers separate components with commas and no
|
|
437
558
|
spaces. ANTLR tolerates a dash separator and one space after a comma. Each
|
|
438
559
|
component greedily consumes an optional leading minus sign, digits, and an
|
|
439
560
|
optional decimal fraction, so the ingester preserves even noncanonical numeric
|
|
440
|
-
shapes for runtime validation.
|
|
561
|
+
shapes for runtime validation. An anchor-bearing text scope uses commas; ANTLR
|
|
562
|
+
tolerates one space after each comma.
|
|
441
563
|
|
|
442
564
|
Apart from the unadvertised three-coordinate text-scope tolerance in
|
|
443
565
|
{§text-scope-semantics}, the runtime rejects invalid arity, out-of-range or
|
|
@@ -448,45 +570,44 @@ does not enforce either condition.
|
|
|
448
570
|
|
|
449
571
|
## §suffix-discipline 8. Suffix Discipline
|
|
450
572
|
|
|
451
|
-
The
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
body content literally contains the close-tag pattern `:OPkeyword`.
|
|
455
|
-
That happens in two scenarios:
|
|
456
|
-
|
|
457
|
-
1. **Nesting plurnk statements inside a body** (recording a plurnk
|
|
458
|
-
transcript, storing examples, etc.). The inner statement's close
|
|
459
|
-
`:OP` would prematurely terminate the outer's body.
|
|
460
|
-
2. **Body content contains `:OPkeyword` as literal text** (e.g., a
|
|
461
|
-
stored JSON object with a value mentioning plurnk syntax).
|
|
573
|
+
The suffix is a turn-wide heading lane. A heading carrying the active lane
|
|
574
|
+
is structural; an otherwise valid PLURNK heading carrying another lane is body
|
|
575
|
+
text. The lane therefore makes literal or nested PLURNK unambiguous.
|
|
462
576
|
|
|
463
577
|
Suffix rules:
|
|
464
578
|
|
|
465
|
-
- `suffix` is `[A-Za-z0-9_]*`, concatenated to
|
|
466
|
-
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
Example — a nested operation inside a suffixed outer body:
|
|
579
|
+
- `suffix` is `[A-Za-z0-9_]*`, concatenated to PLAN or OP with no separator.
|
|
580
|
+
- The H1 PLAN establishes the lane; every real H2 operation heading in that
|
|
581
|
+
turn has the exact same suffix.
|
|
582
|
+
- An empty suffix is accepted only by ANTLR ingestion. Canonical teaching and
|
|
583
|
+
the generated rail use `0` on PLAN and every operation.
|
|
584
|
+
- A body may contain any heading whose suffix differs from the active lane.
|
|
585
|
+
- To carry a nested turn written with lane `0`, choose another suffix for the
|
|
586
|
+
outer turn and repeat it on every outer heading.
|
|
587
|
+
- The GBNF deliberately emits only lane `0`. It cannot emit body content that
|
|
588
|
+
contains a same-lane structural heading; unconstrained producers use another
|
|
589
|
+
outer lane when that representation is required.
|
|
590
|
+
|
|
591
|
+
Example — a lane-0 turn stored inside a lane-2 EDIT body:
|
|
479
592
|
|
|
480
593
|
```
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
594
|
+
# PLAN2
|
|
595
|
+
Store the quoted turn.
|
|
596
|
+
|
|
597
|
+
## EDIT2 (worker:///quoted.plurnk)
|
|
598
|
+
# PLAN0
|
|
599
|
+
Answer from memory.
|
|
600
|
+
|
|
601
|
+
## SEND0 [200]
|
|
602
|
+
Paris.
|
|
603
|
+
|
|
604
|
+
## SEND2 [200]
|
|
605
|
+
Stored the quoted turn.
|
|
485
606
|
```
|
|
486
607
|
|
|
487
|
-
The
|
|
488
|
-
is
|
|
489
|
-
operation, not to EDIT semantics.
|
|
608
|
+
The lane-0 headings are ordinary EDIT body text because the outer turn's
|
|
609
|
+
structural lane is `2`. This rule belongs to section framing and applies to
|
|
610
|
+
every operation, not to EDIT semantics.
|
|
490
611
|
|
|
491
612
|
## 9. SEND Codes
|
|
492
613
|
|
|
@@ -528,7 +649,7 @@ structural:
|
|
|
528
649
|
- §no-idle-102 A **zero-statement turn may not conclude `[102]`** — "continue"
|
|
529
650
|
with nothing submitted is a spin. The GBNF's `tail-0` exits through
|
|
530
651
|
a terminal trie without the `[102]` tail, so the idle turn (`PLAN`
|
|
531
|
-
straight into
|
|
652
|
+
straight into `## SEND0 [102]`) is unemittable; one statement restores
|
|
532
653
|
the full disposition set. The other four stay legal bare (a zero-op
|
|
533
654
|
`[202]` is the engine's obligation check). ANTLR stays tolerant
|
|
534
655
|
(ingest side). A dispatch-emptied turn — ops emitted but failing
|
|
@@ -557,61 +678,60 @@ AST. Generated TypeScript targets the `antlr4ng` runtime.
|
|
|
557
678
|
stateDiagram-v2
|
|
558
679
|
[*] --> DEFAULT
|
|
559
680
|
DEFAULT --> DEFAULT: whitespace or TEXT
|
|
560
|
-
DEFAULT --> SLOTS:
|
|
681
|
+
DEFAULT --> SLOTS: H1 PLANlane or H2 OPlane
|
|
561
682
|
SLOTS --> SIGNAL: signal opener
|
|
562
683
|
SIGNAL --> SLOTS: signal close
|
|
563
684
|
SLOTS --> TARGET: target opener
|
|
564
685
|
TARGET --> TARGET: balanced literals / target escapes
|
|
565
686
|
TARGET --> SLOTS: target close at depth zero
|
|
566
687
|
SLOTS --> SLOTS: scope token
|
|
567
|
-
SLOTS --> BODY:
|
|
568
|
-
BODY --> DEFAULT:
|
|
688
|
+
SLOTS --> BODY: heading line end
|
|
689
|
+
BODY --> DEFAULT: same-lane heading boundary
|
|
690
|
+
BODY --> [*]: end of input
|
|
569
691
|
```
|
|
570
692
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
693
|
+
The first H1 PLAN establishes the turn lane. DEFAULT recognizes only an H1
|
|
694
|
+
PLAN or H2 minted operation carrying that exact lane. SLOTS admits
|
|
695
|
+
operation-appropriate signal, target, and scope openers in any order; the parser
|
|
696
|
+
grammar enforces at-most-once multiplicity. Signal submodes select tags, integer,
|
|
697
|
+
or identifier tokens by operation family. TARGET preserves balanced inner
|
|
698
|
+
parentheses and recognized target escapes. BODY emits opaque text until a
|
|
699
|
+
same-lane heading boundary or EOF.
|
|
576
700
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
DEFAULT recognizes minted operation openers and otherwise emits non-whitespace
|
|
583
|
-
input as TEXT. A `<<word` whose word is not a minted operation remains TEXT.
|
|
584
|
-
Complete native reasoning enclosures are likewise one TEXT token so an operation
|
|
585
|
-
drafted inside pre-PLAN reasoning cannot become the turn anchor.
|
|
701
|
+
A differently suffixed heading stays BODY text. Multi-turn logs are plain
|
|
702
|
+
sequences of independently lane-anchored PLAN turns. Complete native reasoning
|
|
703
|
+
enclosures before PLAN remain one TEXT token so an operation drafted inside
|
|
704
|
+
provider reasoning cannot become the turn anchor.
|
|
586
705
|
|
|
587
706
|
RecordingListener captures lexer and parser failures; AstBuilder adds visitor
|
|
588
|
-
failures. PlurnkErrorStrategy recovers at
|
|
589
|
-
|
|
590
|
-
|
|
707
|
+
failures. PlurnkErrorStrategy recovers at structural heading boundaries where
|
|
708
|
+
possible. EOF is a valid body boundary. An unfinished signal or target produces
|
|
709
|
+
`unparsedTail`; no later input is trustworthy.
|
|
591
710
|
|
|
592
711
|
## §whitespace-contract 11. Whitespace and interstatement text
|
|
593
712
|
|
|
594
|
-
| Location
|
|
595
|
-
|
|
596
|
-
|
|
|
597
|
-
| Between
|
|
598
|
-
|
|
|
599
|
-
| Inside
|
|
600
|
-
| Inside
|
|
601
|
-
| Inside
|
|
602
|
-
| Inside
|
|
603
|
-
| Between
|
|
713
|
+
| Location | Canonical generation | Tolerant ANTLR ingestion |
|
|
714
|
+
|-----------------------------|---------------------------------------|-----------------------------------------------------------|
|
|
715
|
+
| Heading marker | `# PLAN0` or `## OP0` at column zero | The initial PLAN may directly follow leading TEXT; subsequent headings retain exact depth and column |
|
|
716
|
+
| Between OP and suffix | Adjacent | Must remain adjacent |
|
|
717
|
+
| Before each header slot | One ASCII space | Zero or more horizontal whitespace characters |
|
|
718
|
+
| Inside signal | Adjacent values | Horizontal whitespace is ignored; newline is invalid |
|
|
719
|
+
| Inside target | Path alias plus target escapes | Balanced literals tolerated; newline is invalid |
|
|
720
|
+
| Inside scope | Comma-separated numbers | Dash separator and one post-comma space are also accepted |
|
|
721
|
+
| Inside body | Character-perfect | Character-perfect |
|
|
722
|
+
| Between canonical sections | One empty separator line | A directly following structural heading is also admitted |
|
|
723
|
+
| Before the first PLAN | Nothing | Whitespace or TEXT may surface as preamble items without requiring a separator before PLAN |
|
|
604
724
|
|
|
605
725
|
PLURNK never escape-decodes body text: `\n` reaches the owning operation as
|
|
606
726
|
backslash plus `n`. A matcher or executor may interpret those characters under
|
|
607
727
|
its own body dialect. Producers that need a physical newline in literal EDIT
|
|
608
728
|
content emit an actual newline.
|
|
609
729
|
|
|
610
|
-
`parse`
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
730
|
+
`parse` admits TEXT before its PLAN, including without an intervening line
|
|
731
|
+
break, and returns it as ordered text items without assigning semantics. Once
|
|
732
|
+
a heading begins, all nonstructural text belongs to that section body.
|
|
733
|
+
`parseStatements` and `parseClient` admit H2 statements;
|
|
734
|
+
`parseLog` admits consecutive H1 PLAN turns. PLURNK defines no comment syntax.
|
|
615
735
|
|
|
616
736
|
## §public-api 12. Public API
|
|
617
737
|
|
|
@@ -620,20 +740,28 @@ and wire types come from generated schemas; the small hand-maintained parser
|
|
|
620
740
|
types cover ordered parse items and `PlurnkParseError`, which JSON Schema cannot
|
|
621
741
|
express. Consumers never receive ANTLR parse-tree or token types.
|
|
622
742
|
|
|
623
|
-
§turn-shape `PlurnkParser.parse` accepts exactly one model turn. PLAN is the
|
|
624
|
-
first operation, a disposition-coded SEND is the terminal operation, and PLAN
|
|
625
|
-
cannot recur mid-turn. Tolerated TEXT may appear before PLAN
|
|
626
|
-
|
|
627
|
-
|
|
743
|
+
§turn-shape `PlurnkParser.parse` accepts exactly one model turn. H1 PLAN is the
|
|
744
|
+
first operation, a disposition-coded H2 SEND is the terminal operation, and PLAN
|
|
745
|
+
cannot recur mid-turn. Tolerated TEXT may appear only before PLAN; after PLAN,
|
|
746
|
+
nonstructural text is section body content. Missing either anchor or placing a
|
|
747
|
+
same-lane operation after the terminal SEND is an error.
|
|
748
|
+
|
|
749
|
+
§document-fence `PlurnkParser.parse` additionally admits one outer Markdown code
|
|
750
|
+
fence whose opening line is exactly ```` ```plurnk ```` and whose closing line,
|
|
751
|
+
when present, is ```` ``` ````. The fence encloses the complete
|
|
752
|
+
PLAN-through-SEND turn and projects neither text nor body content into the AST.
|
|
753
|
+
Its opener commits the document to either that closer or EOF immediately after
|
|
754
|
+
the complete turn. This is document framing, not another statement grammar, and
|
|
755
|
+
no other parser tier admits it. GBNF continues to shape the paired form.
|
|
628
756
|
|
|
629
757
|
§tier-entrypoints Each parser entry point owns one document tier:
|
|
630
758
|
|
|
631
759
|
| Entry point | Accepted document | Result statement type |
|
|
632
760
|
|--------------------------------|----------------------------------------------------------------|-----------------------|
|
|
633
|
-
| `PlurnkParser.parse` | One PLAN
|
|
761
|
+
| `PlurnkParser.parse` | One PLAN turn: bare with optional TEXT, or outer `plurnk` fence ending at its closer or EOF | `PlurnkStatement` |
|
|
634
762
|
| `PlurnkParser.parseStatements` | Zero or more protocol statements and hidden whitespace | `PlurnkStatement` |
|
|
635
|
-
| `PlurnkParser.parseLog` | One or more
|
|
636
|
-
| `PlurnkParser.parseClient` |
|
|
763
|
+
| `PlurnkParser.parseLog` | One or more consecutive same-lane PLAN-anchored turns | `PlurnkStatement` |
|
|
764
|
+
| `PlurnkParser.parseClient` | H2 protocol statements plus read-shaped LOOK/BUFF commands | `ClientStatement` |
|
|
637
765
|
|
|
638
766
|
Every entry point returns ordered `statement`, `error`, and, where admitted,
|
|
639
767
|
`text` items. When present, {§unparsed-tail-boundary} governs the result's item
|
|
@@ -654,6 +782,7 @@ following supported consumer values. All other root exports are TypeScript types
|
|
|
654
782
|
| `InvalidProblemDetailsError` | Typed failure from `Validator.assertProblemDetails` | {§problem-details} |
|
|
655
783
|
| `InvalidOperationResultError` | Typed failure from `Validator.assertOperationResult` | {§operation-result} |
|
|
656
784
|
| `InvalidTextRegionError` | Typed failure from `Validator.assertTextRegion` | {§text-region} |
|
|
785
|
+
| `InvalidRangeExtentError` | Typed failure from `Validator.assertRangeExtent` | {§range-extent} |
|
|
657
786
|
| `Problems` | RFC 9457 Problem construction | {§problem-details} |
|
|
658
787
|
| `PLURNK_OPS` | Runtime tuple from which the closed `PlurnkOp` union is derived | {§canonical-statement} |
|
|
659
788
|
| `WORKER_NAME`, `RESERVED_AUTHORITIES` | Authority minting predicate and internal reserved names | {§worker-name} |
|
|
@@ -703,7 +832,24 @@ point. A producer supplies all four coordinates or omits the region. It never
|
|
|
703
832
|
substitutes UTF-16 offsets, readable-row indices, or partial coordinates.
|
|
704
833
|
`Validator.assertTextRegion` rejects an end before its start.
|
|
705
834
|
|
|
706
|
-
### §
|
|
835
|
+
### §range-extent 13.2 Range extents
|
|
836
|
+
|
|
837
|
+
`RangeExtent` is the compact wire projection of one line or ordered-result
|
|
838
|
+
selection: `{ unit, total, requested: [first,last], returned?: [first,last] }`.
|
|
839
|
+
`requested` preserves the numeric request, including invalid fractional
|
|
840
|
+
evidence on a failed selection; a one-position request therefore repeats its
|
|
841
|
+
endpoint. Successful selection endpoints are integers. `total` is the complete
|
|
842
|
+
available cardinality.
|
|
843
|
+
`returned` names the inclusive positions actually projected and is absent for
|
|
844
|
+
an empty selection or a failed request. Its endpoints are positive, ordered,
|
|
845
|
+
and no greater than `total`.
|
|
846
|
+
|
|
847
|
+
The transparent coordinates make completion and continuation derivable. The
|
|
848
|
+
shape has no separate `complete`, `next`, or all-results instruction. Exact
|
|
849
|
+
text-coordinate selections use {§text-region} instead. `Validator.assertRangeExtent`
|
|
850
|
+
enforces both the schema and the relational endpoint invariants.
|
|
851
|
+
|
|
852
|
+
### §entry-read-result 13.3 Client entry reads
|
|
707
853
|
|
|
708
854
|
`EntryReadResult` is the exact transport-neutral projection of one entry. It
|
|
709
855
|
does not expose workspace IDs, storage owner IDs, split scheme/pathname fields,
|
|
@@ -719,7 +865,6 @@ scope, or other persistence columns.
|
|
|
719
865
|
| `entryId` | Positive durable entry identifier |
|
|
720
866
|
| `target` | Client selector for the resolved entry, with any channel fragment removed |
|
|
721
867
|
| `channels` | Every channel for a full read, or exactly the selected channel for a sliced read |
|
|
722
|
-
| `tags` | Unique non-empty entry tags |
|
|
723
868
|
|
|
724
869
|
| Channel field | Contract |
|
|
725
870
|
|-----------------|---------------------------------------------------------------------------------------------------------------|
|
|
@@ -736,7 +881,7 @@ offset beyond the current end returns empty content at `contentLength`, not the
|
|
|
736
881
|
unbounded requested offset. `Validator.assertEntryReadResult` enforces the
|
|
737
882
|
schema, this suffix invariant, and Problem status equality.
|
|
738
883
|
|
|
739
|
-
### 13.
|
|
884
|
+
### 13.4 Operation results
|
|
740
885
|
|
|
741
886
|
§operation-result Every public PLURNK operation returns one `OperationResult`:
|
|
742
887
|
|
|
@@ -750,7 +895,7 @@ fields and Problem Details extension members remain open. A malformed result is
|
|
|
750
895
|
an internal producer contract violation; it is not converted into a second
|
|
751
896
|
model-facing failure envelope.
|
|
752
897
|
|
|
753
|
-
### 13.
|
|
898
|
+
### 13.5 Problem Details
|
|
754
899
|
|
|
755
900
|
§problem-details `ProblemDetails` requires `type`, `title`, `status`, and `detail`;
|
|
756
901
|
`instance` is optional until a durable host can attach the occurrence URI.
|
|
@@ -780,13 +925,13 @@ Internal invariant violations throw and preserve their cause. An external
|
|
|
780
925
|
protocol may require its own error envelope; its adapter maps that envelope to
|
|
781
926
|
or from the canonical Problem without creating another PLURNK failure contract.
|
|
782
927
|
|
|
783
|
-
### 13.
|
|
928
|
+
### 13.6 Notices
|
|
784
929
|
|
|
785
930
|
§notice A `Notice` is a transient, nonterminal observation. It cannot determine durable
|
|
786
931
|
failure truth, lifecycle, scheduling, or recovery. Sharing a renderer with
|
|
787
932
|
Problems does not merge their semantics.
|
|
788
933
|
|
|
789
|
-
### §client-display-capabilities 13.
|
|
934
|
+
### §client-display-capabilities 13.7 Client display capabilities
|
|
790
935
|
|
|
791
936
|
`ClientDisplayCapabilities` is the transport-neutral installed-capability
|
|
792
937
|
projection used by external clients. It is an ordered array of closed,
|
|
@@ -824,7 +969,7 @@ class PlurnkParseError extends Error {
|
|
|
824
969
|
```
|
|
825
970
|
|
|
826
971
|
§parser-position Parser source locations are points, not text regions. An AST
|
|
827
|
-
statement's `position` identifies the first
|
|
972
|
+
statement's `position` identifies the first `#` of its heading; a diagnostic
|
|
828
973
|
identifies the offending or recovery point; a text item and `unparsedTail.from`
|
|
829
974
|
identify the first point at which that item or undefined tail begins. A
|
|
830
975
|
statement constructed without retained parsed source uses `UNKNOWN_POSITION`,
|
|
@@ -850,48 +995,40 @@ and 3.30.2](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html).
|
|
|
850
995
|
| Source | Boundary |
|
|
851
996
|
|-------------|----------------------------------------------------------------------------------------|
|
|
852
997
|
| `"lexer"` | Token-level failure, such as an unrecognized character or malformed `<L>` integer. |
|
|
853
|
-
| `"parser"` | Structural failure, such as
|
|
998
|
+
| `"parser"` | Structural failure, such as the wrong heading depth or slot order. |
|
|
854
999
|
| `"visitor"` | Semantic AST-construction failure, such as an invalid matcher dialect or signal shape. |
|
|
855
1000
|
|
|
856
1001
|
`severity` distinguishes a hard error from a non-fatal advisory. The parser is
|
|
857
1002
|
the sole and complete owner of syntax-error messaging because it holds the
|
|
858
1003
|
parse state, lexer mode, and expected-token set that no consumer has. It
|
|
859
1004
|
produces the final diagnostic message, deduplicated expected-token lists,
|
|
860
|
-
turn-shape imperatives (begin with
|
|
861
|
-
these targeted diagnostics:
|
|
862
|
-
|
|
863
|
-
- §invented-closer-advisory **Invented closer.** When the forgiving parser
|
|
864
|
-
swallows a `<<Word…:Word` heredoc whose keyword is a known op confusion
|
|
865
|
-
(`<<CLOSE` → did you mean `<<FOLD`), it emits a `warning`-severity near-miss
|
|
866
|
-
advisory. On a never-closed body, when the swallowed text carries an
|
|
867
|
-
`:ALLCAPS` tag that is not the op's closer, the `unparsedTail` reason names it
|
|
868
|
-
(`found \`:COMPARISON_TASK\`, which is body text - the closer echoes the op's
|
|
869
|
-
name`) so a cap-cut runaway's recovery turn learns what happened, not just
|
|
870
|
-
that something did.
|
|
1005
|
+
turn-shape imperatives (begin with `# PLAN0`, end with a terminal
|
|
1006
|
+
`## SEND0 [code]`), and these targeted diagnostics:
|
|
1007
|
+
|
|
871
1008
|
- §signal-scope-redirect **EXEC scope in the signal slot.** When EXEC's
|
|
872
1009
|
`[signal]` slot (executor-ident mode) hits a leading `-` or digit —
|
|
873
1010
|
mark-shaped `<timeout, poll>` scope content mistyped into the brackets — the
|
|
874
1011
|
lexer message becomes `timeout/poll ride the \`<scope>\` slot; try
|
|
875
|
-
|
|
1012
|
+
\`## EXEC0 <-1,300>\`` instead of a raw `unrecognized character`. The redirect is
|
|
876
1013
|
EXEC-scoped because its signal mode is exclusive; SEND/KILL are untouched.
|
|
877
1014
|
- §matcher-body-redirect **Matcher body in the slot region.** When the
|
|
878
|
-
post-target
|
|
879
|
-
unambiguous
|
|
880
|
-
list. Slash-led regex and XPath are excluded because
|
|
881
|
-
|
|
882
|
-
- §
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1015
|
+
post-target header region begins with `$`, `~`, or `@`, the lexer redirects
|
|
1016
|
+
the unambiguous matcher to the first body line instead of returning the
|
|
1017
|
+
generic slot list. Slash-led regex and XPath are excluded because `/` can be
|
|
1018
|
+
target data.
|
|
1019
|
+
- §combined-anchor-line-redirect **Combined anchor and line number in a scope.**
|
|
1020
|
+
A text-coordinate scope containing `@hash:L` or `@hash L` is one bounded hard
|
|
1021
|
+
error: `a scope position accepts one line coordinate; use the \`@hash\` anchor
|
|
1022
|
+
without its displayed line number`. A malformed header scope is consumed as
|
|
1023
|
+
one token, while a COPY/MOVE destination selection fails at its visitor
|
|
1024
|
+
boundary; neither produces a punctuation cascade.
|
|
887
1025
|
- §misplaced-target-advisory **Mutation target in the signal slot.** When a
|
|
888
1026
|
mutating op (EDIT/COPY/MOVE) parses with a null `(target)` and a path-shaped
|
|
889
1027
|
`[signal]` element (a `/` or a dotted extension), the message redirects the
|
|
890
|
-
path into `(…)` (
|
|
891
|
-
\`[…]\` tag slot; a target goes in \`(…)\`. Try
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
genuine tags-only slip is not mis-steered toward a path it lacks.
|
|
1028
|
+
path into `(…)` (`\`## EDIT0\` has no \`(target)\` - that path sits in the
|
|
1029
|
+
\`[…]\` tag slot; a target goes in \`(…)\`. Try \`## EDIT0 (path)\``). It is
|
|
1030
|
+
gated on a path-shaped signal so a genuine additive-tag signal is not mis-steered
|
|
1031
|
+
toward a path it lacks.
|
|
895
1032
|
|
|
896
1033
|
§error-shape The diagnostic class determines how much guidance the parser may
|
|
897
1034
|
provide:
|
|
@@ -901,20 +1038,20 @@ provide:
|
|
|
901
1038
|
| Hard fact | `severity: "error"` | One concise observed fact and violated constraint in PLURNK vocabulary. |
|
|
902
1039
|
| Targeted hard redirect | `severity: "error"` | One canonical correction only when parser state makes the intended structure unambiguous. |
|
|
903
1040
|
| Non-fatal advisory | `severity: "warning"` | One narrowly gated likely mistake and canonical alternative; input remains admitted. |
|
|
904
|
-
| Boundary loss | `unparsedTail` | Where trust ends,
|
|
1041
|
+
| Boundary loss | `unparsedTail` | Where trust ends, which header slot remains open, and why later input is undefined. |
|
|
905
1042
|
|
|
906
|
-
All messages use PLURNK protocol vocabulary:
|
|
907
|
-
|
|
908
|
-
|
|
1043
|
+
All messages use PLURNK protocol vocabulary: heading, lane, signal, target,
|
|
1044
|
+
scope, line marker, body, section boundary, or space between slots. They never
|
|
1045
|
+
expose ANTLR rule or token names. They refer to a slot or
|
|
909
1046
|
feature rather than an implementation rule. Generic tutoring, speculative
|
|
910
1047
|
intent, coordinate restatement, and multiple repair strategies are forbidden.
|
|
911
1048
|
|
|
912
1049
|
Examples of canonical hard facts:
|
|
913
1050
|
|
|
914
|
-
- `unrecognized character '
|
|
1051
|
+
- `unrecognized character '<' in target`
|
|
915
1052
|
- `unrecognized character ':' in signal`
|
|
916
1053
|
- `unrecognized character 'X' in statement header`
|
|
917
|
-
- `
|
|
1054
|
+
- `a turn must begin with \`# PLAN0\``
|
|
918
1055
|
- `expected ')'; got ':'`
|
|
919
1056
|
|
|
920
1057
|
Each malformed statement produces at most one hard error. The first recorded
|
|
@@ -949,6 +1086,6 @@ runtime constructs this; the parser provides the fields):
|
|
|
949
1086
|
"column": 12,
|
|
950
1087
|
"source": "parser",
|
|
951
1088
|
"severity": "error",
|
|
952
|
-
"message": "
|
|
1089
|
+
"message": "target slot of `## READ0` opened at line 1 but never closed - add `)`"
|
|
953
1090
|
}
|
|
954
1091
|
```
|