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