mustflow 2.116.1 → 2.116.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/package.json +1 -1
  2. package/templates/default/i18n.toml +72 -6
  3. package/templates/default/locales/en/.mustflow/skills/INDEX.md +37 -11
  4. package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/SKILL.md +477 -0
  5. package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/compiler-diagnostics-abi-linker-checklist.md +778 -0
  6. package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/compiler-generators-properties-checklist.md +501 -0
  7. package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/compiler-test-strategy-differential-checklist.md +498 -0
  8. package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/debug-symbol-symbolication-checklist.md +412 -0
  9. package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/ir-design-ssa-pass-pipeline-checklist.md +759 -0
  10. package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/miscompile-reduction-ir-checklist.md +434 -0
  11. package/templates/default/locales/en/.mustflow/skills/cross-platform-filesystem-safety/SKILL.md +55 -36
  12. package/templates/default/locales/en/.mustflow/skills/cross-platform-filesystem-safety/references/path-containment-handle-checklist.md +251 -0
  13. package/templates/default/locales/en/.mustflow/skills/file-upload-security-review/SKILL.md +133 -32
  14. package/templates/default/locales/en/.mustflow/skills/file-upload-security-review/references/file-upload-parser-ssrf-resource-checklist.md +306 -0
  15. package/templates/default/locales/en/.mustflow/skills/formal-verification-review/SKILL.md +310 -0
  16. package/templates/default/locales/en/.mustflow/skills/formal-verification-review/references/formal-concurrency-model-checking-smt-checklist.md +457 -0
  17. package/templates/default/locales/en/.mustflow/skills/formal-verification-review/references/formal-contracts-modeling-checklist.md +434 -0
  18. package/templates/default/locales/en/.mustflow/skills/formal-verification-review/references/formal-memory-bounds-ci-checklist.md +509 -0
  19. package/templates/default/locales/en/.mustflow/skills/fuzz-harness-review/SKILL.md +439 -0
  20. package/templates/default/locales/en/.mustflow/skills/fuzz-harness-review/references/fuzz-harness-campaign-checklist.md +379 -0
  21. package/templates/default/locales/en/.mustflow/skills/fuzz-harness-review/references/fuzz-oracle-triage-ci-checklist.md +307 -0
  22. package/templates/default/locales/en/.mustflow/skills/idempotency-integrity-review/SKILL.md +48 -28
  23. package/templates/default/locales/en/.mustflow/skills/idempotency-integrity-review/references/operation-ordering-stale-write-checklist.md +259 -0
  24. package/templates/default/locales/en/.mustflow/skills/input-boundary-validation-review/SKILL.md +329 -0
  25. package/templates/default/locales/en/.mustflow/skills/input-boundary-validation-review/references/input-boundary-security-checklist.md +319 -0
  26. package/templates/default/locales/en/.mustflow/skills/input-event-synchronization-review/SKILL.md +306 -0
  27. package/templates/default/locales/en/.mustflow/skills/input-event-synchronization-review/references/input-session-state-checklist.md +298 -0
  28. package/templates/default/locales/en/.mustflow/skills/input-event-synchronization-review/references/remote-input-transport-interaction-checklist.md +328 -0
  29. package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/SKILL.md +353 -0
  30. package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-diagnostics-recovery-checklist.md +267 -0
  31. package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-execution-closure-performance-checklist.md +428 -0
  32. package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-gc-verification-checklist.md +457 -0
  33. package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-semantics-runtime-checklist.md +391 -0
  34. package/templates/default/locales/en/.mustflow/skills/modal-loop-reentrancy-review/SKILL.md +294 -0
  35. package/templates/default/locales/en/.mustflow/skills/modal-loop-reentrancy-review/references/modal-loop-reentrancy-checklist.md +290 -0
  36. package/templates/default/locales/en/.mustflow/skills/modal-loop-reentrancy-review/references/nested-modal-state-lifetime-checklist.md +297 -0
  37. package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/SKILL.md +252 -0
  38. package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/references/dns-network-resolution-checklist.md +394 -0
  39. package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/references/language-symbol-resolution-checklist.md +282 -0
  40. package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/references/module-package-loader-resolution-checklist.md +352 -0
  41. package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/SKILL.md +103 -17
  42. package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/cst-ast-lowering-checklist.md +260 -0
  43. package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/lexer-tokenization-checklist.md +397 -0
  44. package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/tree-serialization-compatibility-checklist.md +164 -0
  45. package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/tree-traversal-rewrite-checklist.md +209 -0
  46. package/templates/default/locales/en/.mustflow/skills/race-condition-review/SKILL.md +68 -11
  47. package/templates/default/locales/en/.mustflow/skills/race-condition-review/references/race-reproduction-memory-model-checklist.md +268 -0
  48. package/templates/default/locales/en/.mustflow/skills/routes.toml +151 -0
  49. package/templates/default/locales/en/.mustflow/skills/session-handoff-integrity-review/SKILL.md +343 -0
  50. package/templates/default/locales/en/.mustflow/skills/session-handoff-integrity-review/references/session-auth-stream-resume-checklist.md +413 -0
  51. package/templates/default/locales/en/.mustflow/skills/session-handoff-integrity-review/references/session-handoff-protocol-checklist.md +485 -0
  52. package/templates/default/locales/en/.mustflow/skills/two-phase-transition-integrity-review/SKILL.md +267 -0
  53. package/templates/default/locales/en/.mustflow/skills/two-phase-transition-integrity-review/references/admission-decision-recovery-checklist.md +308 -0
  54. package/templates/default/locales/en/.mustflow/skills/two-phase-transition-integrity-review/references/two-phase-transition-checklist.md +229 -0
  55. package/templates/default/locales/en/.mustflow/skills/ui-dispatch-lifecycle-review/SKILL.md +300 -0
  56. package/templates/default/locales/en/.mustflow/skills/ui-dispatch-lifecycle-review/references/ui-affinity-event-loop-checklist.md +277 -0
  57. package/templates/default/locales/en/.mustflow/skills/ui-dispatch-lifecycle-review/references/ui-dispatch-lifecycle-checklist.md +292 -0
  58. package/templates/default/manifest.toml +115 -1
@@ -0,0 +1,260 @@
1
+ # CST to AST Lowering Checklist
2
+
3
+ Use this checklist when a parser produces a concrete syntax tree, surface AST, semantic AST, HIR,
4
+ or another lowered tree consumed by diagnostics, formatting, refactoring, compilation, or execution.
5
+
6
+ ## Contents
7
+
8
+ 1. [Layer contract ledger](#layer-contract-ledger)
9
+ 2. [Lossless CST invariants](#lossless-cst-invariants)
10
+ 3. [Surface AST boundary](#surface-ast-boundary)
11
+ 4. [AST schema and local invariants](#ast-schema-and-local-invariants)
12
+ 5. [Absence, recovery, and synthetic states](#absence-recovery-and-synthetic-states)
13
+ 6. [Tokens, trivia, parentheses, and source views](#tokens-trivia-parentheses-and-source-views)
14
+ 7. [Lowering map and origin evidence](#lowering-map-and-origin-evidence)
15
+ 8. [Semantic-sensitive syntax](#semantic-sensitive-syntax)
16
+ 9. [Evaluation order, scope, and reference semantics](#evaluation-order-scope-and-reference-semantics)
17
+ 10. [Identity, side tables, and snapshots](#identity-side-tables-and-snapshots)
18
+ 11. [Tree verification](#tree-verification)
19
+ 12. [Test matrix](#test-matrix)
20
+ 13. [Failure matrix](#failure-matrix)
21
+ 14. [Invariants and handoffs](#invariants-and-handoffs)
22
+
23
+ ## Layer contract ledger
24
+
25
+ Classify a tree by what it may lose, not by whether its type name contains `AST`, `syntax`, or
26
+ `parse tree`. Write one row per layer:
27
+
28
+ | Layer | Must preserve | May normalize | Primary consumers |
29
+ | --- | --- | --- | --- |
30
+ | Source and tokens | Original units, token boundaries, raw spelling, trivia, invalid input | Derived line and display coordinates | lexer, diagnostics, syntax tree |
31
+ | Lossless CST | Every source unit, delimiters, missing and unexpected syntax, exact order | Parser-only rule wrappers when reconstruction remains exact | formatter, refactoring, IDE, lowering |
32
+ | Surface AST | User-visible language constructs, semantic punctuation, order, scope owners, syntax origin | Pure grammar wrappers and non-semantic trivia | binder, type checker, source tools |
33
+ | HIR or core tree | Explicit evaluation order, normalized constructs, generated temporaries, origin map | Surface sugar and redundant grouping | semantic analysis, optimization, execution |
34
+ | Side tables | Symbols, types, constants, control-flow facts, phase and snapshot identity | Derived query indexes | later analyses and tools |
35
+
36
+ For every removed field or node, name the first layer that is allowed to remove it and the consumer
37
+ that no longer needs it. A successful parse is not evidence that the loss boundary is correct.
38
+
39
+ ## Lossless CST invariants
40
+
41
+ - Account for every original source unit exactly once through tokens, trivia, skipped input, or
42
+ unexpected-syntax nodes.
43
+ - Represent a required but absent token as a zero-width missing token at one insertion point. Do not
44
+ print it as if the user wrote it.
45
+ - Keep unexpected tokens and recovery spans distinct from accepted children. Do not discard them or
46
+ coerce them into plausible normal tokens.
47
+ - Preserve delimiter tokens and their exact order even when a later AST represents the resulting
48
+ structure without punctuation nodes.
49
+ - Make reconstruction of the original source possible for valid and malformed input without asking
50
+ the AST to guess whitespace, comments, escapes, or invalid bytes.
51
+ - Keep grammar-helper nodes only when they carry observable structure, recovery boundaries, or a
52
+ stable incremental responsibility. Do not expose every factored production as a public tree API.
53
+
54
+ ## Surface AST boundary
55
+
56
+ Use the question `must a downstream semantic or source-aware consumer distinguish these forms?` to
57
+ decide whether two CST forms may become one AST form.
58
+
59
+ - Collapse grammar wrappers that exist only for precedence encoding, conflict removal, or parser
60
+ control flow.
61
+ - Preserve constructs whose evaluation, scope, binding, control flow, arity, reference behavior,
62
+ diagnostics, or refactoring behavior differs.
63
+ - Classify punctuation as disposable separator, semantic field, or structural discriminator before
64
+ removing it. An operator normally becomes a typed field; a comma, newline, or delimiter can decide
65
+ tuple, elision, statement, pattern, or argument structure.
66
+ - Preserve explicit grouping through a syntax reference, grouping node, or ordered delimiter ranges
67
+ when formatting, refactoring, diagnostics, or user-intent preservation needs it.
68
+ - Keep a surface construct until a dedicated lowering step can prove that desugaring preserves
69
+ evaluation count, evaluation order, exceptions, scope, and source origin.
70
+ - Introduce a separate HIR or core layer when source tools need surface constructs but execution and
71
+ analysis need normalized forms. Do not make one node schema alternate between both contracts.
72
+
73
+ ## AST schema and local invariants
74
+
75
+ - Use closed tagged unions for material categories and variants. Make visitors exhaustive when a new
76
+ expression, statement, declaration, pattern, type, or target is added.
77
+ - Separate `Expr`, `Stmt`, `Decl`, `Pattern`, `TypeNode`, and `AssignmentTarget` when their legal
78
+ positions and invariants differ.
79
+ - Expose children through named fields. Keep repeated children in immutable source-order sequences;
80
+ derive maps or sets as indexes rather than replacing order-bearing syntax.
81
+ - Encode cardinality in field types: required child, optional child, or non-null immutable sequence.
82
+ Do not overload one null value with absence, error, not-yet-computed, and empty collection.
83
+ - Construct a complete immutable node in one step. Keep partially initialized builders private and
84
+ prevent incomplete nodes from escaping.
85
+ - Enforce local invariants in constructors and context-dependent invariants in a separate validation
86
+ pass. A child constructor cannot decide whether `break`, `await`, or a binding is legal in its
87
+ eventual parent context.
88
+ - Give structural children one logical parent. Share immutable storage nodes or interned payloads,
89
+ and derive parent views separately when structural reuse is required.
90
+
91
+ ## Absence, recovery, and synthetic states
92
+
93
+ Model distinct states explicitly:
94
+
95
+ | State | Meaning |
96
+ | --- | --- |
97
+ | `Absent` | An optional construct was not written. |
98
+ | `Missing` | Required syntax was absent and recovery inserted a placeholder. |
99
+ | `Synthetic` | A tool or lowering pass created the node. |
100
+ | `Empty` | The user wrote a valid empty construct. |
101
+ | `Elided` | The language permits an omitted slot whose position remains meaningful. |
102
+ | `Error` | Source was present but no normal semantic node can truthfully represent it. |
103
+
104
+ - Keep category-specific error nodes such as `ErrorExpr`, `ErrorStmt`, or `ErrorPattern` so later
105
+ passes remain type-safe without inventing executable meaning.
106
+ - Never replace missing names, numbers, operands, or delimiters with empty names, zero values, null
107
+ literals, or normal tokens unless the language explicitly defines that recovery semantics.
108
+ - Give synthetic nodes a generation reason, originating node identity, and primary or secondary
109
+ source origins. Do not rely on a single `isSynthetic` flag.
110
+ - Prevent compilation, execution, or serialization as valid code when a required error or missing
111
+ state remains, unless the consumer explicitly accepts an incomplete-tree contract.
112
+
113
+ ## Tokens, trivia, parentheses, and source views
114
+
115
+ - Keep original source storage and a lossless token stream as the source-aware truth. Let AST nodes
116
+ refer to syntax instead of copying partial source fragments into every semantic node.
117
+ - Preserve token kind, canonical raw range, raw spelling or source slice, cooked value or invalid
118
+ state, and applicable lexical provenance separately.
119
+ - Distinguish node span, full span including trivia, name span, operator span, and delimiter spans.
120
+ Make each consumer request the range it actually needs.
121
+ - Treat token gaps as the canonical trivia location. Compute leading, trailing, dangling, preamble,
122
+ end-of-file, and unattached ownership through a deterministic attachment policy.
123
+ - Preserve whitespace as source slices or typed runs when exact reconstruction matters. Do not
124
+ collapse tabs, spaces, line endings, escaped newlines, or other whitespace into one count.
125
+ - Preserve nested parentheses and per-pair ranges through CST or syntax references. One boolean
126
+ cannot represent repeated grouping, comments inside delimiters, or exact edit boundaries.
127
+ - Reuse unchanged source slices when printing unchanged syntax and format only changed subtrees.
128
+ Reconcile boundary trivia explicitly instead of reformatting the whole file.
129
+
130
+ ## Lowering map and origin evidence
131
+
132
+ Create a CST-to-AST loss ledger and a lowering entry for every concrete variant:
133
+
134
+ - input CST kind and accepted recovery states;
135
+ - output surface-AST kind and named fields;
136
+ - tokens, trivia, delimiters, and wrappers preserved by syntax reference;
137
+ - information intentionally consumed or normalized;
138
+ - diagnostics or error node produced when required evidence is missing;
139
+ - origin mapping for one-to-one, many-to-one, and one-to-many transformations;
140
+ - verifier expected before and after the transformation.
141
+
142
+ Do not lower irreversible semantic constructs inside parser callbacks. Publish a complete CST first,
143
+ then run a deterministic lowering pass whose inputs and outputs can be inspected independently.
144
+ Reject an unhandled concrete variant rather than silently returning null or a generic node.
145
+
146
+ For generated temporaries and expanded control flow, map the lowered nodes back to the originating
147
+ surface construct and material subexpressions. Preserve both a primary diagnostic origin and any
148
+ secondary origins needed to explain duplicated or reordered structure.
149
+
150
+ ## Semantic-sensitive syntax
151
+
152
+ - Preserve parser decisions for contextual keywords, generic delimiters, patterns, and other forms
153
+ that cannot be reconstructed from token spelling alone.
154
+ - Preserve tuple, argument, sequence, grouping, and elision distinctions before discarding commas or
155
+ delimiters.
156
+ - Preserve statement boundaries and newline-sensitive decisions made by the grammar. Do not rebuild
157
+ them from a trivia-stripped token list.
158
+ - Carry raw spelling and exact language-defined literal representation until conversion has a
159
+ precise overflow, invalid-escape, suffix, and normalization contract.
160
+ - Keep pattern and assignment-target structure separate from expression structure when read, write,
161
+ delete, binding, default, and rest rules differ.
162
+ - Use the parser's already established precedence and associativity tree. Do not flatten operators
163
+ and re-fold them under a second, potentially divergent table.
164
+
165
+ ## Evaluation order, scope, and reference semantics
166
+
167
+ - Lower compound assignment, optional access, logical assignment, comprehensions, iteration sugar,
168
+ async forms, and similar constructs with explicit temporaries that evaluate each material operand
169
+ the language-defined number of times and in the defined order.
170
+ - Preserve exceptions and side effects while introducing temporaries. Validate read, operation,
171
+ write, short-circuit, and cleanup order separately.
172
+ - Preserve receiver or reference identity when a member call differs from loading a function value
173
+ and calling it independently.
174
+ - Represent scope owners, binders, defaults, guards, and child evaluation regions explicitly. Do not
175
+ flatten a construct whose children execute in different scopes.
176
+ - Keep duplicate and ordered elements in source order when evaluation, override, reflection,
177
+ diagnostics, or tooling can observe them.
178
+ - Record desugaring decisions in the origin map so diagnostics point to user-written syntax rather
179
+ than invented temporaries or control-flow nodes.
180
+
181
+ ## Identity, side tables, and snapshots
182
+
183
+ - Keep `NodeId`, source span, and structural hash distinct. A span is a location, a hash compares
184
+ content, and a node identity names one occurrence in a versioned tree.
185
+ - Exclude spans, trivia, and raw spelling from semantic structural equality when they do not affect
186
+ meaning. Maintain a separate syntax or source hash when exact spelling matters.
187
+ - Keep resolved symbols, inferred types, constants, control-flow facts, and other phase results in
188
+ generation-aware side tables keyed by node and snapshot identity. Do not replace syntax fields
189
+ with resolved objects in place.
190
+ - Reuse syntax identity after an edit only when the unchanged subtree and its parser context remain
191
+ valid. Invalidate dependent side-table entries by semantic dependency, not only by text overlap.
192
+ - Version syntax references and origin maps so a node cannot silently point into an obsolete source
193
+ snapshot.
194
+ - When nodes move without semantic change, preserve semantic comparability without claiming that the
195
+ old and new source occurrences are the same identity.
196
+
197
+ ## Tree verification
198
+
199
+ Run a verifier after parsing and after every material lowering stage. Check:
200
+
201
+ - unique node identities within the declared identity scope;
202
+ - absence of structural cycles and illegal multi-parent ownership;
203
+ - child category, field cardinality, and source-order constraints;
204
+ - valid source ranges, delimiter ordering, and snapshot ownership;
205
+ - allowed missing, error, synthetic, and elided states for the current phase;
206
+ - complete lowering coverage and no parser-only wrapper in phases that forbid it;
207
+ - valid origin mapping for generated, merged, and split nodes;
208
+ - phase-specific rules such as no surface sugar after core lowering;
209
+ - side-table generation and node-snapshot compatibility.
210
+
211
+ Make verifier failures diagnostic and bounded. A malformed tree must not crash its printer, walker,
212
+ or diagnostic renderer before the verifier can identify the broken invariant.
213
+
214
+ ## Test matrix
215
+
216
+ - Reconstruct exact original source from the CST for valid, invalid, incomplete, mixed-line-ending,
217
+ escaped, commented, and delimiter-heavy inputs.
218
+ - Assert surface-AST shape for punctuation-sensitive forms, operator pairs and triples, grouping,
219
+ contextual syntax, patterns, targets, scopes, and error nodes.
220
+ - Compare AST results across grammar refactors that change parser-only wrapper productions.
221
+ - Trace side effects and exceptions through sugar lowering to prove operand count, order, receiver,
222
+ scope, short-circuit, and cleanup behavior.
223
+ - Exercise every absence state and verify that missing or erroneous syntax never becomes an ordinary
224
+ executable value.
225
+ - Move and edit comments around empty containers, delimiters, preambles, and EOF; verify deterministic
226
+ trivia ownership and minimal unchanged-source edits.
227
+ - Compare incremental CST, AST, origin maps, and side-table invalidation with a fresh full pipeline
228
+ after edit sequences.
229
+ - Mutate each AST field and phase tag to prove the verifier rejects wrong categories, null required
230
+ fields, duplicate identities, cycles, stale origins, and forbidden phase nodes.
231
+ - Test both semantic equality and exact syntax equality so a source move or spelling change does not
232
+ accidentally poison semantic caches or disappear from source-aware tools.
233
+
234
+ ## Failure matrix
235
+
236
+ | Symptom | Evidence to require |
237
+ | --- | --- |
238
+ | Formatter loses comments or whitespace. | Token gaps, trivia attachment, full spans, syntax references, and unchanged-slice reuse. |
239
+ | Grammar refactor changes public AST. | Concrete-variant lowering map, wrapper normalization rule, and AST golden diff. |
240
+ | Valid-looking AST came from malformed input. | Missing and unexpected CST nodes, category-specific error node, and execution gate. |
241
+ | Compound assignment evaluates a target twice. | Surface sugar node, temporary plan, evaluation trace, and origin map. |
242
+ | Rename or diagnostic points at the wrong text. | Snapshot identity, name span, raw token range, syntax reference, and origin generation. |
243
+ | Incremental analysis reuses stale facts. | Node and snapshot identity, changed semantic dependency, side-table generation, and full-pipeline differential. |
244
+ | Parentheses or commas change meaning after lowering. | Parser decision, structural discriminator, surface-AST shape, and semantic equality oracle. |
245
+ | Tree walker crashes after successful parse. | Constructor invariants, phase verifier, error-node schema, cycle and category checks. |
246
+
247
+ ## Invariants and handoffs
248
+
249
+ - Every source unit is owned by the lossless syntax layer before any abstraction occurs.
250
+ - Every information loss names the owning lowering stage and a consumer contract that permits it.
251
+ - Every normal AST node represents written or explicitly synthetic meaning; recovery never forges a
252
+ user-written value.
253
+ - Every order-bearing construct remains ordered until a later phase proves order unobservable.
254
+ - Every generated node has an origin and every side-table fact has a snapshot generation.
255
+ - Every lowering stage has an input verifier, output verifier, and differential or semantic oracle.
256
+ - Use `parser-engineering-review` for CST, AST, recovery, source, and incremental ownership.
257
+ - Use `compiler-engineering-review` for HIR or IR semantic refinement after the parser boundary.
258
+ - Use `interpreter-engineering-review` when lowered nodes directly define runtime evaluation.
259
+ - Use `name-resolution-integrity-review` when bindings and symbol side tables are the disputed layer.
260
+ - Use `observability-debuggability-review` when durable tree or lowering diagnostics change.
@@ -0,0 +1,397 @@
1
+ # Lexer and Tokenization Contract Checklist
2
+
3
+ Use this reference when `parser-engineering-review` reaches a lexer, tokenizer, token cache,
4
+ source-position layer, or incremental relexing boundary. Treat the examples as collision probes,
5
+ not as syntax that every language must accept. Freeze the language-specific decision before changing
6
+ implementation or tests.
7
+
8
+ ## Contents
9
+
10
+ 1. Token representation
11
+ 2. Candidate selection and longest match
12
+ 3. Identifiers and keywords
13
+ 4. Operators, lexical modes, and goals
14
+ 5. Encoding, Unicode, newlines, and positions
15
+ 6. Strings and escapes
16
+ 7. Numbers, comments, and malformed input
17
+ 8. Streaming outcomes and recovery diagnostics
18
+ 9. Incremental and large-input behavior
19
+ 10. Hostile-input and resource budgets
20
+ 11. Differential, fuzz, and property tests
21
+ 12. Standards and implementation anchors
22
+
23
+ ## 1. Token representation
24
+
25
+ Define one token contract before implementing scanner branches. Keep these concerns separate:
26
+
27
+ - `kind`: stable lexical classification, including explicit malformed or unterminated kinds when
28
+ callers need recovery.
29
+ - `span`: canonical half-open source range, normally `[startByte, endByte)` over the original byte
30
+ stream. Never make a decoded or normalized buffer the silent source of truth.
31
+ - `raw`: source slice identity or raw spelling. Avoid allocating a copied `rawText` for every token
32
+ when an immutable source buffer can provide the same lossless view.
33
+ - `cooked`: decoded escape, normalized identifier key, or literal value representation. Make an
34
+ invalid or unavailable cooked value explicit instead of overwriting raw source.
35
+ - `positions`: typed derived coordinates such as line index, UTF-16 offset, code-point offset, or
36
+ display column. Name the unit and conversion owner.
37
+ - `trivia`: whitespace and comments with raw spans plus applicable newline effects. Do not erase a
38
+ line break merely because the surrounding comment is skipped by the parser.
39
+ - `diagnostics`: stable code, severity, arguments, primary and related raw spans, fix-its, and
40
+ recovery information. Preserve a token boundary even when cooking fails, and keep message
41
+ rendering out of the scanner.
42
+
43
+ Require token and trivia spans to account for every original source byte exactly once, except for
44
+ declared zero-width synthetic insertions. Keep parser-inserted missing tokens separate from lexical
45
+ tokens that cover real input.
46
+
47
+ ## 2. Candidate selection and longest match
48
+
49
+ Define selection as data, not rule-file folklore:
50
+
51
+ 1. Start every candidate at the same input position.
52
+ 2. Continue scanning while at least one candidate can progress.
53
+ 3. Whenever a candidate accepts, record its last accepting rule, comparison end, actual token end,
54
+ and any capture state required to emit it.
55
+ 4. When no candidate can progress, choose the greatest comparison end. Use an explicit, stable
56
+ priority only when comparison lengths tie.
57
+ 5. Rewind to the chosen token end and emit. If no candidate ever accepted, consume one bounded
58
+ invalid source unit while preserving its raw byte range and emit an error token.
59
+
60
+ Keep `comparisonEnd` distinct from `tokenEnd` when lookahead or trailing context participates in
61
+ candidate comparison but must remain unconsumed. Reject equal-length, equal-priority overlaps during
62
+ grammar or table generation. Reordering declarations must not change output when explicit priority
63
+ is unchanged.
64
+
65
+ Build fixed operators and punctuators as a trie or equivalent DFA. Generate collision cases for
66
+ every prefix relation rather than maintaining hand-written `if` order. Include follower predicates
67
+ in the accepting condition when the next code point changes whether a candidate is lexically valid.
68
+
69
+ Examples to classify together include:
70
+
71
+ - `>`, `>=`, `>>`, `>>=`
72
+ - `=`, `==`, `===`, `=>`
73
+ - `1`, `1.`, `1.0`, `1e3`, `1e+3`
74
+ - `.5`, `1..2`, `1...2`, `1.foo`, `1._x`, `1.e2`
75
+ - a complete fixed token at EOF and the same token followed by each permitted token-start class
76
+
77
+ ## 3. Identifiers and keywords
78
+
79
+ Scan the complete identifier before hard-keyword classification. Use an exact lookup on the
80
+ language-defined semantic spelling; never split a keyword prefix from a longer identifier.
81
+
82
+ Record these policy choices explicitly:
83
+
84
+ - hard keywords emitted as fixed token kinds;
85
+ - contextual keywords retained as identifiers or annotated with a parser-consumed hint;
86
+ - whether identifier escapes are accepted and whether lookup uses raw or cooked spelling;
87
+ - whether identifiers are normalized, rejected when non-normalized, or compared without
88
+ normalization;
89
+ - whether keyword matching is case-sensitive, ASCII-folded, or Unicode-folded;
90
+ - the pinned Unicode data version and the identifier profile, normally based on `XID_Start` and
91
+ `XID_Continue` plus a named set of additions or removals.
92
+
93
+ Do not call locale-dependent lowercase functions for language keywords. Do not normalize the whole
94
+ source buffer. Apply identifier normalization or folding only at the declared semantic-key boundary
95
+ while retaining raw spelling and byte spans.
96
+
97
+ Keep lexical validity separate from identifier-security diagnostics. Mixed-script, confusable,
98
+ bidirectional-control, and restricted-format checks belong to a named security pass unless the
99
+ language contract explicitly makes them lexical errors.
100
+
101
+ Probe at least `if`, `ifx`, `xif`, `while2`, `_return`, `return_`, escaped spellings that cook to a
102
+ keyword, normalized and decomposed equivalents, mixed scripts, and EOF immediately after an
103
+ identifier.
104
+
105
+ ## 4. Operators, lexical modes, and goals
106
+
107
+ Make the current lexical mode physically restrict the candidate rule set. Use stack frames when a
108
+ mode can nest or must retain parameters such as delimiter count, interpolation brace depth, comment
109
+ depth, indentation state, or embedded-language identity.
110
+
111
+ Do not reduce nested strings or interpolation to one `insideString` boolean. Emit structural string
112
+ segments and ordinary expression tokens so the parser can see embedded expressions while preserving
113
+ raw text segments.
114
+
115
+ Recognize comment openers only in modes where comments can begin. Recognize string prefixes only
116
+ after the complete opener is confirmed; otherwise return to ordinary identifier or punctuation
117
+ rules. Preserve `/`, `//`, `/*`, and `/=` as competing candidates in code mode without applying
118
+ comment rules inside strings or comments.
119
+
120
+ When a token class depends on syntactic context, define a parser-supplied lexical goal or an
121
+ equivalent integrated scanner-parser contract. Do not infer division versus regular expression,
122
+ generic delimiter versus shift, or template tail versus right brace from a brittle previous-token
123
+ heuristic.
124
+
125
+ ## 5. Encoding, Unicode, newlines, and positions
126
+
127
+ Separate raw-byte acquisition, decoding, lexical matching, and external position conversion:
128
+
129
+ - Decode using the declared source encoding while retaining a mapping from scanner code-point
130
+ boundaries to original byte offsets.
131
+ - On invalid encoding, preserve the exact failing byte range and guarantee progress. At an
132
+ uncommitted chunk boundary, distinguish an incomplete code-unit sequence that needs more input
133
+ from a sequence already proven invalid. Do not silently collapse distinct invalid byte sequences
134
+ into indistinguishable source.
135
+ - Recognize a BOM only at a contract-defined stream start. If an encoding declaration exists, sniff
136
+ only its bounded raw-byte prefix and define conflict behavior before full decoding.
137
+ - Pin the Unicode data version used by compiler, formatter, language server, and token cache. Treat a
138
+ Unicode version change as a compatibility change with identifier fixtures.
139
+ - Treat code points as lexical matching units unless the language explicitly says otherwise. Use
140
+ grapheme clusters and display width only for user-interface rendering.
141
+ - Define the accepted line terminator set. Count CRLF as one terminator sequence when supported and
142
+ distinguish physical lines from logical lines.
143
+ - Keep byte offsets, UTF-16 code-unit offsets, code-point offsets, line indices, and display columns
144
+ as distinct types or named conversions. Negotiate the external protocol position encoding instead
145
+ of assuming compiler byte columns equal editor columns.
146
+
147
+ Test multibyte identifiers, combining marks, emoji before diagnostics, CRLF and lone CR where
148
+ supported, mixed newline files, tabs, invalid encoding followed by valid syntax, and round trips
149
+ between the canonical byte span and every external position unit.
150
+
151
+ ## 6. Strings and escapes
152
+
153
+ Scan strings with a state machine, not one lazy regular expression. Separate opener, ordinary text,
154
+ escape, interpolation opener, closing delimiter, forbidden newline, and EOF transitions.
155
+
156
+ - Consume an escape production atomically when its backslash is seen. Do not decide whether a quote
157
+ is escaped by inspecting only the immediately preceding character.
158
+ - Preserve raw spelling and compute cooked content separately. Keep a stable token or segment when
159
+ escape decoding fails.
160
+ - Store parameterized raw-string delimiter state from the opener and accept only an exactly matching
161
+ closer. Bound delimiter length according to the language contract.
162
+ - For interpolation, push an expression frame with its own brace depth. Permit nested strings and
163
+ interpolations by stacking frames rather than sharing one global depth.
164
+ - End an unterminated single-line string at its declared recovery boundary, usually before the
165
+ newline. Let multiline strings reach their declared closer or EOF. Emit an explicit unterminated
166
+ token or segment and leave the scanner in a progress-making state.
167
+ - Define every escape family: exact digit count or bounded variable count, valid scalar range,
168
+ surrogate rejection, unknown-escape policy, and whether line continuation contributes cooked
169
+ content.
170
+
171
+ Probe even and odd backslash runs before quotes, invalid escapes, escaped newlines, interpolation
172
+ with nested braces, nested interpolation, raw delimiters containing shorter false closers, prefixes
173
+ that are also valid identifier starts, newline recovery, and EOF after every opener state.
174
+
175
+ ## 7. Numbers, comments, and malformed input
176
+
177
+ Keep unary signs outside numeric tokens unless the sign occurs in a grammar-defined exponent.
178
+ Specify numeric syntax independently from host-language conversion:
179
+
180
+ - base prefixes and the minimum digits after each prefix;
181
+ - digit classes per base;
182
+ - separator positions, repetition, and trailing policy;
183
+ - fraction, exponent marker, optional exponent sign, and required exponent digits;
184
+ - suffix start and allowed suffixes;
185
+ - dot follower restrictions and collisions with range or member-access tokens;
186
+ - forbidden followers after an otherwise valid numeric prefix;
187
+ - the recovery boundary for a malformed numeric token.
188
+
189
+ Lex numeric structure first and perform value conversion in a separate literal-semantic pass. Do not
190
+ let host `parseFloat`, fixed-width integer overflow, or locale parsing define lexical validity.
191
+
192
+ When the language wants one useful diagnostic, consume inputs such as `0xG`, `1e+foo`, `123abc`, or
193
+ invalid separator runs as one bounded malformed token instead of reporting a valid prefix followed
194
+ by misleading unrelated tokens. The exact malformed boundary is language policy and must be tested.
195
+
196
+ For malformed candidates, keep the accepted-language grammar narrow and define a separate bounded
197
+ candidate envelope for recovery. Record `firstFault`, `terminationReason`, and a capped
198
+ `secondaryFaultCount`; do not rescan the same token once per bad character. Keep these locations
199
+ separate:
200
+
201
+ - `primarySpan` or `faultOffset`: what the diagnostic should underline first;
202
+ - `recoverySpan`: all source consumed to regain a stable token boundary;
203
+ - `originSpan`: the opener or prefix that created the current lexical state; and
204
+ - a related termination span for newline, EOF, or a mismatched closer.
205
+
206
+ For an unterminated construct, the primary span normally points at the opener rather than an empty
207
+ EOF location. EOF or the forbidden newline can be a related span.
208
+
209
+ Preserve comments as trivia when formatting, documentation, source maps, or newline-sensitive syntax
210
+ needs them. Define whether block comments nest and whether a comment containing a line terminator has
211
+ newline semantics. At EOF, emit one unterminated-comment trivia item from opener to EOF.
212
+
213
+ ## 8. Streaming outcomes and recovery diagnostics
214
+
215
+ Treat a buffer boundary, committed source EOF, malformed input, and resource exhaustion as different
216
+ outcomes. A streaming scanner should expose an equivalent of:
217
+
218
+ - `Token(token)`: emits a token that covers real input, or one declared bounded state-changing
219
+ insertion;
220
+ - `EndOfInput`: a terminal outcome observed once, not a repeatedly emitted zero-width token;
221
+ - `NeedMoreInput`: current bytes are a valid prefix of a candidate and source EOF is not yet known;
222
+ and
223
+ - `ResourceLimitExceeded(kind, offset, observed, limit)`: bounded termination with structured
224
+ evidence rather than an allocation failure or hang.
225
+
226
+ At committed EOF, emit an identifier, number, or fixed token when the current state accepts. Convert
227
+ an incomplete encoding sequence or open string, interpolation, raw delimiter, or comment to the
228
+ declared malformed or unterminated result. Do not return `NeedMoreInput` after EOF is known, and do
229
+ not emit the same zero-width error or EOF result twice.
230
+
231
+ Model buffer refill as a lexer state transition. Preserve or relocate every live position and state:
232
+ `cursor`, `limit`, `tokenStart`, last accepting marker and captures, trailing-context marker,
233
+ decoder partial state, mode stack, lexical goal, and EOF knowledge. A refill that keeps only the
234
+ cursor silently corrupts tokens spanning chunks.
235
+
236
+ Keep diagnostics as structured data, for example `code`, `severity`, `args`, `primarySpan`,
237
+ `relatedSpans`, `fixIts`, `recoverySpan`, `snapshotId`, and `mode`. The low-level scanner
238
+ should not localize or render a finished sentence.
239
+
240
+ Define synchronization by lexical mode. A code-mode invalid byte, string escape, interpolation
241
+ expression, raw string, and nested comment do not share one safe recovery delimiter. Coalesce
242
+ adjacent secondary failures into a contamination region, cap diagnostic volume, and emit one
243
+ aggregate omission diagnostic when the cap is reached.
244
+
245
+ Treat a fix-it as executable behavior. Apply it to a temporary immutable snapshot, lex again, and
246
+ require the intended token plus downstream token-and-state convergence. Reject a fix-it that only
247
+ makes the highlighted bytes look plausible while shifting the lexer into a different mode.
248
+
249
+ ## 9. Incremental and large-input behavior
250
+
251
+ Checkpoint every state that can affect future candidates, including mode stack, lexical goal,
252
+ delimiter parameters, comment or interpolation depth, indentation or newline state, decoder partial
253
+ state, and any previous significant-token category required by the language contract. Checkpoint
254
+ density may be adaptive, but checkpoint contents must be complete.
255
+
256
+ Make checkpoint serialization a tested continuation contract: lexing a suffix after
257
+ serialize/deserialize must equal uninterrupted lexing. Restart before an edit at a checkpoint valid
258
+ for the new immutable snapshot. Stop only when canonical token kind, length, flags, and complete
259
+ outgoing state converge with the old snapshot at the same source position. A block hash is only a
260
+ fast inequality filter; verify actual fields after a hash match. Never use one equal token, a fixed
261
+ number of equal tokens, one line, or a fixed character radius as the correctness boundary.
262
+
263
+ Tie work and publication to `snapshotId`. Check cancellation or staleness at bounded work
264
+ intervals, discard partial results, and publish atomically only when the result still targets the
265
+ current snapshot. Arbitrary parallel chunks are unsafe unless each starts from a proven complete
266
+ state.
267
+
268
+ Keep the hot path narrow:
269
+
270
+ - use an ASCII fast path and a Unicode slow path whose results are identical at their boundary;
271
+ - if delimiter search is vectorized, test scalar tails and every chunk alignment;
272
+ - store source ranges in compact token records and move diagnostics, cooked values, and uncommon
273
+ payloads to side tables;
274
+ - defer unescaping, numeric conversion, normalization, and interning until a consumer requests them;
275
+ - compute line and display columns from a line-start index rather than updating every coordinate on
276
+ every byte; and
277
+ - align source and token blocks so edits replace bounded blocks, using relative offsets plus an
278
+ aggregate index instead of rewriting all following absolute positions.
279
+
280
+ Define snapshot lifetime and release policy. Zero-copy is not free if a ten-byte token retains an
281
+ obsolete multi-gigabyte snapshot; use chunk ownership or promote a small long-lived slice to owned
282
+ storage when that is cheaper.
283
+
284
+ Measure the editing product, not only clean-file throughput: `relexedBytesPerEdit`,
285
+ `reusedTokenRatio`, allocations per edit, diagnostic latency, peak live bytes, and p50/p95/p99 edit
286
+ latency. Keep counters available in tests so a wall-clock threshold is not the only complexity
287
+ oracle.
288
+
289
+ ## 10. Hostile-input and resource budgets
290
+
291
+ Use one request-scoped multidimensional budget. Applicable counters include input bytes, raw token
292
+ bytes, cooked or decoded bytes, emitted token and trivia count, diagnostic count, nesting depth,
293
+ checkpoint count, retained source bytes, allocation bytes, and cooperative work units. Charge before
294
+ allocation or publication and return the exhausted dimension.
295
+
296
+ - Keep raw-token and cooked-value limits separate. Escape decoding, normalization, and conversion
297
+ can expand or allocate even when the raw spelling is bounded.
298
+ - Keep the recognition hot path linear. Do not hand hostile text to a backtracking regular-expression
299
+ engine or recursively descend once per nested comment opener.
300
+ - Track nested comments and interpolation with checked iterative counters. Bound retained opener
301
+ history instead of storing every nesting position.
302
+ - Scan a huge token as a range while updating only bounded metadata. Do not append every byte to a
303
+ builder or join all source chunks merely to classify the token.
304
+ - Bound output amplification: a small input must not create unbounded tiny tokens, diagnostics,
305
+ checkpoints, or interned identifiers. Coalesce compatible trivia and contamination regions.
306
+ - Treat NUL as input data unless the language forbids it. Keep EOF as separate state, and prove any
307
+ sentinel or padding cannot become a valid lexeme suffix or cause an out-of-bounds read.
308
+ - Use checked addition, multiplication, growth, and narrowing for positions, token-table sizes,
309
+ display-coordinate conversion, and allocation requests.
310
+ - Bound snapshot retention and identifier interning. Prefer request-local interning with a distinct
311
+ identifier budget and collision-resistant storage.
312
+ - Check cooperative cancellation after bounded bytes or state transitions, at refills and mode
313
+ changes, and inside very long tokens. Discard the incomplete snapshot result on cancellation.
314
+
315
+ ## 11. Differential, fuzz, and property tests
316
+
317
+ Require applicable properties in addition to example fixtures:
318
+
319
+ - Raw token, trivia, skipped, and error spans are half-open, ordered, non-overlapping, and partition
320
+ the input without gaps; concatenating their raw slices reconstructs the exact input bytes.
321
+ - Every scanner step consumes source, reaches committed EOF, returns `NeedMoreInput`, or performs
322
+ one declared bounded state-changing insertion.
323
+ - No longer valid candidate exists at the chosen token start under the active mode and lexical goal.
324
+ - Equal-length selection follows explicit priority and remains stable when declaration order changes.
325
+ - Every fixed operator prefix pair receives generated surrounding-character and EOF cases.
326
+ - Hard keyword prefixes remain identifiers when the complete spelling is not an exact keyword.
327
+ - One-shot and chunked scanning agree for all short split positions and biased splits inside
328
+ multibyte encodings, escapes, numbers, comments, delimiters, and last-accept checkpoints.
329
+ - Full and incremental lexing agree after every edit in randomized edit sequences, including edits
330
+ that propagate string, comment, delimiter, indentation, or lexical-goal state.
331
+ - Checkpoint serialize/deserialize followed by suffix scanning equals uninterrupted scanning.
332
+ - Malformed-input scanning terminates within token, diagnostic, transition, revisit, allocation, and
333
+ retained-source budgets.
334
+
335
+ For differential testing, normalize each implementation to an observation such as
336
+ `(canonicalKind, rawStart, rawEnd, flags)`. Filter specification-permitted differences before
337
+ comparison, and treat disagreement as a candidate defect rather than majority proof. Keep an
338
+ intentionally slow reference lexer independent of production tables, character classifiers, and
339
+ candidate-selection helpers; sharing the same recognition code only reproduces the same bug twice.
340
+
341
+ Combine a grammar-aware generator with raw byte mutation. Bias lengths to zero, one, maximum minus
342
+ one, maximum, maximum plus one, powers of two, chunk size boundaries, delimiter lengths, and Unicode
343
+ sequence widths. Add metamorphic relations only with explicit preconditions, such as inserting
344
+ trivia where trivia is grammar-neutral or changing chunk partitions without changing bytes.
345
+
346
+ Instrument transitions, byte revisits, allocations, maximum stack or mode depth, and reprocessed
347
+ bytes. Use sanitizers or equivalent memory-safety instrumentation where supported. When shrinking a
348
+ failure, minimize not only input bytes but also edit history, chunk splits, checkpoint placement,
349
+ options, and the normalized mismatch while preserving the triggering phenomenon.
350
+
351
+ Keep minimized failures as regression seeds. Classify whether each seed proves a language-contract
352
+ decision, implementation defect, host-runtime disagreement, or unsupported input.
353
+
354
+ ## 12. Standards and implementation anchors
355
+
356
+ Use these primary sources as examples of explicit lexical contracts, not as permission to copy one
357
+ language's decisions into another:
358
+
359
+ - [flex input matching](https://westes.github.io/flex/manual/Matching.html): longest input first,
360
+ then tie handling, including trailing-context comparison length.
361
+ - [ECMAScript lexical grammar](https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html):
362
+ longest input elements, numeric followers, line terminators, templates, and parser-selected
363
+ lexical goals.
364
+ - [Rust token grammar](https://doc.rust-lang.org/reference/tokens.html): raw delimiters, escapes,
365
+ identifier classes, and dot follower restrictions for floating literals.
366
+ - [ANTLR lexer rules](https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md): mode-specific
367
+ sublexers and lexer mode transitions.
368
+ - [Go language specification](https://go.dev/ref/spec): comment boundaries, comment newline effects,
369
+ numeric separators, and semicolon insertion inputs.
370
+ - [Python lexical analysis](https://docs.python.org/3/reference/lexical_analysis.html): source
371
+ decoding, bounded encoding declarations, physical and logical lines, strings, and indentation.
372
+ - [Unicode UAX #31](https://www.unicode.org/reports/tr31/): identifier profiles, `XID_Start`,
373
+ `XID_Continue`, normalization, and version-sensitive Unicode data.
374
+ - [Unicode UTS #39](https://www.unicode.org/reports/tr39/): identifier restriction and confusable
375
+ detection mechanisms that belong in a separately declared security policy.
376
+ - [Unicode UAX #29](https://www.unicode.org/reports/tr29/): grapheme boundaries for display and
377
+ cursor behavior rather than ordinary lexer grammar units.
378
+ - [Language Server Protocol 3.17](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/):
379
+ negotiated position encoding and the UTF-16 compatibility default.
380
+ - [Go `bufio.Scanner` source](https://go.dev/src/bufio/scan.go): partial-input split outcomes,
381
+ progress checks, invalid advance rejection, token-size limits, buffer relocation, and empty-token
382
+ termination guards.
383
+ - [Tree-sitter external scanners](https://tree-sitter.github.io/tree-sitter/creating-parsers/4-external-scanners.html):
384
+ complete scanner-state serialization, explicit EOF distinct from NUL, column-query cost, and
385
+ zero-width-token loop hazards.
386
+ - [re2c end-of-input and refill manual](https://re2c.org/manual/manual_d.html#eof):
387
+ cursor, limit, token start, markers, refill relocation, sentinel, padding, and bounds-check
388
+ invariants.
389
+ - [RE2](https://github.com/google/re2): linear-time matching, bounded memory, non-recursive
390
+ execution, and graceful budget exhaustion for untrusted patterns and text.
391
+ - [Clang diagnostics internals](https://clang.llvm.org/docs/InternalsManual.html#the-diagnostics-subsystem):
392
+ stable diagnostic IDs, typed arguments, source ranges, renderer separation, and executable fix-it
393
+ constraints.
394
+ - [Rust `rustc_lexer`](https://github.com/rust-lang/rust/blob/main/compiler/rustc_lexer/src/lib.rs):
395
+ compact token results that retain termination and malformed-literal state for later diagnosis.
396
+ - [LLVM libFuzzer](https://llvm.org/docs/LibFuzzer.html): deterministic and bounded fuzz targets,
397
+ structured mutators, corpus reduction, sanitizers, and memory or timeout failure oracles.