export declare const LANGUAGE_REFERENCE = "\n\n# rill\n\n> Scripting language designed for machine-generated code. LLMs generate rill scripts; humans review and debug. Data flows through pipes (`->`), not assignment. Variables use `$` prefix. No null, no exceptions, no truthiness.\n\nFor progressive disclosure, see [ref-llms.txt](ref-llms.txt) (index) and [llm/*.txt](llm/) fragments. This file is the full single-source bundle.\n\n---\n\n# rill cheatsheet\n\nDefault context for any rill task. Covers the 7 critical differences, syntax, `$` binding, and callable types. Read first.\n\n## The 7 critical differences\n\n### 1. No assignment operator\n\n Wrong: x = 5 Mainstream: x = value\n Right: 5 => $x rill: value => $x\n\n`->` pipes a value to the next operation. `=>` captures a value AND continues the chain.\n\n \"hello\" => $x -> .upper => $y # $x=\"hello\", $y=\"HELLO\"\n\n### 2. No null or undefined\n\nEmpty values (`\"\"`, `0`, `false`, `list[]`, `dict[]`) exist. \"No value\" cannot be represented.\n\n $dict.field ?? \"default\" # default if vacant\n $str -> .empty ? \"was empty\" # explicit check\n\n### 3. No truthiness\n\nConditions must be boolean. No coercion. Negation also requires boolean.\n\n Wrong: \"\" ? \"yes\" ! \"no\" Right: \"\" -> .empty ? \"yes\" ! \"no\"\n Wrong: 0 ? \"yes\" ! \"no\" Right: (0 == 0) ? \"yes\" ! \"no\"\n Wrong: !\"hello\" Right: \"hello\" -> .empty -> (!$)\n\n### 4. Variables lock to first type\n\n \"hello\" => $x\n 42 => $x # ERROR: cannot assign number to string variable\n\n### 5. No variable shadowing\n\nChild scopes can READ parent variables but cannot WRITE or redeclare. Loop bodies cannot mutate outer state.\n\n Wrong: 0 => $count\n list[1, 2, 3] -> seq({ $count + 1 => $count }) # runtime error\n\n Right: list[1, 2, 3] -> fold(0, { $@ + $ }) # 6\n\n`for` does not exist. Use `seq`, `fan`, `fold`, `acc`, `filter`, `sort`, or `while`.\n\n### 6. Errors halt \u2014 recover with `guard`\n\nNo try/catch. Failures throw runtime errors (uncatchable) or produce **invalid values** that halt on access. Recover access halts with `guard { }` or `retry { }`. Inspect with `.!`, `.!code`, `.!message`.\n\n### 7. Value semantics\n\nAll copies are deep. All comparisons are by value. No object identity.\n\n list[1, 2, 3] == list[1, 2, 3] # true\n list[1, 2] => $a\n $a => $b # $b is an independent deep copy\n\n## Syntax quick reference\n\n Variables: $name (always prefixed with $)\n Strings: \"hello {$var}\" # interpolation with {}\n \"\"\"multiline\"\"\" # also interpolates\n Numbers: 42, 3.14, -7\n Booleans: true, false\n Atoms: #TIMEOUT # interned identifiers (must start uppercase)\n Lists: list[1, 2, 3]\n list[...$xs, 4] # spread\n Dicts: dict[name: \"alice\", age: 30]\n dict[1: \"one\", 2: \"two\"] # number keys (incl. negative: dict[-1: \"neg\"])\n dict[true: \"yes\", false: \"no\"] # boolean keys\n dict[list[\"a\", \"b\"]: 1] # multi-key: dict[a: 1, b: 1]\n dict[$keyVar: value] # variable key (must eval to string)\n dict[(\"{$a}{$b}\"): value] # computed key (must eval to string)\n Tuples: tuple[1, 2, 3]\n Ordered: ordered[a: 1, b: 2] # named-arg unpacking\n Closures: |x| ($x + 1) # explicit\n { $ + 1 } # block, implicit $\n Type annot: \"hi\" => $x:string\n Modules: use => $g\n Extensions: use => $llm\n Comments: # single line only\n Frontmatter: ---\\nkey: value\\n--- # YAML at top of script\n\nCRITICAL: `keyword[` must have NO space before `[`. `list [1]` is a parse error.\n\nUnregistered atoms collapse to the #R001 fallback: for any two names the host never registered, #FOO == #BAR is true and both render as #R001. Register atoms via the host/extension. See errors for pre-registered atoms.\n\n## Pipes and `$` binding\n\n`$` is the current piped value. Its meaning depends on context:\n\n| Context | `$` contains |\n|---|---|\n| `-> { body }` | piped value |\n| `-> seq({ })` / `fan({ })` / `filter({ })` | current item |\n| `-> fold(i, { })` / `acc(i, { })` | current item (`$@` = accumulator) |\n| `while (cond) do { }` | accumulated value |\n| `cond ? a ! b` | pipe value entering the conditional (either branch) |\n| `\\|\\|{ $.field }` in dict | the containing dict |\n\nImplied `$`: bare `.method` means `$ -> .method`. `\"hello\" -> .upper` is `\"hello\" -> $.upper`.\n\n**Pipe binding when `->` targets a callable.** If no top-level `$` appears in the argument list, the piped value is auto-prepended. If any top-level `$` appears, every `$` resolves to the piped value (no auto-prepend). Closure boundaries (`{ ... }`) hide their inner `$` from the scan. See `callables` for the full table.\n\n $list -> filter({ $.active }) # filter($list, { ... }); closure $ is late-bound\n [1,2,3] -> fold(0, { $@ + $ }) # fold([1,2,3], 0, ...) \u2014 list auto-prepended\n 10 -> $fmt(1, $, 0) # $fmt(1, 10, 0) \u2014 explicit placement\n\nAlways prefer implicit `$`:\n\n .method # over $.method\n func # over func($)\n $fn # over $fn($)\n\nDon't capture just to continue a chain. Use line continuation. Capture only when reused.\n\n## Callable types\n\n| Type | Source | Examples |\n|---|---|---|\n| Closure | Script-defined | `\\|x\\| { $x * 2 }`, `{ $ + 1 }` |\n| Built-in | Shipped with runtime | `log`, `json`, `range`, `repeat`, `chain` |\n| Host | Registered by host | `$app.fetch()` (hoisted via `use => $app`) |\n\nThe `$` prefix disambiguates:\n\n name() -> built-in or host call\n $name() -> closure invocation\n $name -> variable reference\n name -> dict key literal\n\n## Operator precedence (highest to lowest)\n\n1. Member access: `.field`, `[index]`\n2. Type operators: `:type`, `:?type`\n3. Unary: `-`, `!`\n4. `*` `/` `%`\n5. `+` `-`\n6. Comparison: `==` `!=` `<` `>` `<=` `>=`\n7. `&&`\n8. `||`\n9. `??`\n10. `->`\n11. `=>`\n\nUse parentheses to override.\n\n## Collection operators\n\n| Operator | Signature | Semantics |\n|---|---|---|\n| `seq` | `seq(list, closure)` | Transform each item sequentially; returns all body results |\n| `fan` | `fan(list, closure)` | Transform each item in parallel; returns all body results |\n| `filter` | `filter(list, closure)` | Keep items where body returns `true` |\n| `fold` | `fold(list, init, closure)` | Reduce to single value; `$@` = accumulator |\n| `acc` | `acc(list, init, closure)` | Like `fold` but emits accumulator at each step |\n| `sort` | `sort(list, key_fn?)` | Stable ascending sort; dict input returns `ordered` |\n| `take` | `take(list, n: int) -> list[T]` | First n elements; `n < 0` halts `#INVALID_INPUT`; `n > MAX_ITER` clamps |\n| `skip` | `skip(list, n: int) -> list[T]` | Drop first n elements; `n < 0` halts `#INVALID_INPUT`; n past length \u2192 empty |\n| `cycle` | `cycle(list) -> iterator[T]` | Repeat input indefinitely as iterator; empty input \u2192 empty; bound at consumer |\n| `batch` | `batch(list, n: int, options?) -> stream[list[T]]` | Chunks of n; `drop_partial: true` discards trailing short chunk |\n| `window` | `window(list, n: int, step: int = n) -> stream[list[T]]` | Sliding windows of n; default step=n (non-overlapping); `step > n` makes gaps |\n| `start_when` | `start_when(list, predicate: closure) -> stream[T]` | Yield from first match onward; predicate must return `bool` |\n| `stop_when` | `stop_when(list, predicate: closure) -> stream[T]` | Yield through first match (inclusive); predicate must return `bool` |\n| `pass { body }` | `pass { body }` | Side-effect block; pipe value flows through unchanged; halts in body propagate |\n| `pass` | `pass { body }` | Side-effect block; suppresses catchable halts in body; `on_error: #IGNORE` is the only valid option (else RILL-P004) |\n\n## Script return values\n\n| Return value | Exit code |\n|---|---|\n| `true` / non-empty string | 0 |\n| `false` / empty string | 1 |\n| `list[0, \"message\"]` | 0 with message |\n| `list[1, \"message\"]` | 1 with message |\n\n---\n\n# rill anti-patterns\n\nWrong/Right pairs aimed at TypeScript and Python reflexes. Load when generating fresh code.\n\n## Assignment\n\n Wrong: x = 5\n Right: 5 => $x\n\n Wrong: let user = \"alice\"\n Right: \"alice\" => $user\n\n Wrong: const PI = 3.14\n Right: 3.14 => $pi\n\n## Variable references\n\n Wrong: x.upper\n Right: $x -> .upper\n\n Wrong: print(name)\n Right: log($name) # or $name -> log\n\n## Curly braces (dict literals)\n\nIn rill, `{ ... }` is a block (closure body, loop body, etc.), not a dict literal. Dicts use `dict[...]`.\n\n Wrong: {name: \"alice\"}\n Right: dict[name: \"alice\"]\n\n Wrong: {} # empty block, not an empty dict\n Right: dict[]\n\n Wrong: {name: \"alice\", age: 30}\n Right: dict[name: \"alice\", age: 30]\n\n Wrong: {user: {name: \"alice\"}}\n Right: dict[user: dict[name: \"alice\"]]\n\n Wrong: list[{a: 1}, {a: 2}]\n Right: list[dict[a: 1], dict[a: 2]]\n\n Wrong: dict[user-id: 1] # bare identifiers must be snake_case\n Right: dict[\"user-id\": 1] # quote the key for non-identifier names\n\n## Truthy conditions\n\n Wrong: $name ? \"have name\" ! \"no name\"\n Right: $name -> .empty ? \"no name\" ! \"have name\"\n\n Wrong: $count ? \"some\" ! \"none\"\n Right: ($count > 0) ? \"some\" ! \"none\"\n\n Wrong: $list ? \"items\" ! \"empty\"\n Right: $list -> .empty ? \"empty\" ! \"items\"\n\n Wrong: !$value\n Right: $value -> .empty # for strings/lists/dicts\n Right: ($value == 0) # for numbers\n Right: !$bool # only on actual booleans\n\n## Loops\n\n Wrong: for item in list { ... }\n Right: $list -> seq({ ... }) # sequential, returns all results\n Right: $list -> fan({ ... }) # parallel, returns all results\n\n Wrong: for (let i = 0; i < n; i++) { ... }\n Right: range(0, $n) -> seq({ ... })\n\n Wrong: let total = 0\n for x in list { total += x }\n Right: $list -> fold(0, { $@ + $ }) # 6 for list[1,2,3]\n\n Wrong: while (x < 10) { x = x + 1 }\n Right: 0 -> while ($ < 10) do { $ + 1 }\n\n## Reassignment inside loops\n\n Wrong: 0 => $sum\n $items -> seq({ $sum + $.price => $sum }) # halts: outer var reassigned\n\n Right: $items -> fold(0, { $@ + $.price }) # 0 + p1 + p2 + ...\n Right: $items -> acc(0, { $@ + $.price }) # list of running totals\n\n## Try/catch\n\n Wrong: try { fetch(url) } catch (e) { fallback }\n Right: retry { $app.fetch($url) } => $r\n $r ?? \"fallback\"\n\n Wrong: try { JSON.parse(s) } catch { null }\n Right: guard { $app.parse_json($s) } => $out # JSON parsing is host-provided; rill has no built-in parser\n $out.! ? \"parse failed\" ! $out\n\n## Null and undefined\n\n Wrong: x === null\n Right: $x.! # is this an invalid value?\n Right: $x -> .empty # is this an empty container?\n\n Wrong: x ?? default # JS nullish coalescing\n Right: $x ?? \"default\" # rill: vacant (empty OR invalid) coalescing\n\n Wrong: dict[a: undefined]\n Right: dict[a: \"\"] # explicit empty\n\n## String operations\n\n Wrong: \"Hello \" + name\n Right: \"Hello {$name}\" # interpolation\n Right: \"Hello \" -> { $ + $name } # if you really need + (number-string ERROR)\n\n Wrong: name.toUpperCase()\n Right: $name -> .upper\n\n Wrong: arr.length\n Right: $arr.len # property, not method call\n\n## Array methods\n\n Wrong: arr.map(x => x * 2)\n Right: $arr -> fan({ $ * 2 }) # parallel\n Right: $arr -> seq({ $ * 2 }) # sequential\n\n Wrong: arr.filter(x => x > 0)\n Right: $arr -> filter({ $ > 0 })\n\n Wrong: arr.reduce((acc, x) => acc + x, 0)\n Right: $arr -> fold(0, { $@ + $ })\n\n Wrong: arr.sort()\n Right: $arr -> sort # stable ascending\n Right: $arr -> sort -> .reverse # descending\n Right: $arr -> sort({ $.score }) # sort by extracted key\n Right: $arr -> sort({ tuple[$.a, $.b] }) # multi-key\n\n Wrong: arr[arr.length - 1]\n Right: $arr[-1] # negative index from end\n\n## Object access\n\n Wrong: obj.missing # undefined or error\n Right: $obj.missing ?? \"default\" # vacant fallback\n Right: $obj.?missing # boolean: does field exist?\n\n Wrong: obj[\"computed-\" + key]\n Right: $obj.(\"{$prefix}-{$key}\") # computed key\n\n## Function calls vs closures\n\n Wrong: $double(5) # if $double is a built-in or host fn\n Right: double(5) # no $ for built-in/host calls\n\n Wrong: log($x) # if log was assigned to $log\n Right: $log($x) # script closures need $\n\n Wrong: |x| ($x * 2) => double # capture name needs $\n Right: |x| ($x * 2) => $double\n\n## Whitespace traps\n\nOnly the first halts. The rest parse and run; the checker reports them at\ninfo level. Write them tight anyway.\n\n list [1, 2, 3] # ERROR (RILL-P007): keyword and bracket must be adjacent\n $obj. field # SPACING_MEMBER: dot must touch the field name\n $obj .field # SPACING_MEMBER: same, on the other side\n $x->.upper # SPACING_OPERATOR: pipe needs spaces both sides\n\n---\n\n# rill control flow\n\nConditionals, loops, branching, and the collection-operator picker.\n\n## Conditional\n\n cond ? then_expr ! else_expr\n cond ? then_expr # without else: returns current $ when false; halts RILL-R005 if $ unbound\n\nPiped form (`$` becomes condition):\n\n value -> ? then_expr ! else_expr\n\nMulti-line (`?` and `!` start continuation lines):\n\n condition\n ? \"yes\"\n ! \"no\"\n\n $val -> .eq(\"A\") ? \"a\"\n ! .eq(\"B\") ? \"b\"\n ! \"c\"\n\n## Loops\n\nPre-condition (`while ... do`):\n\n init -> while ($ < 10) do { $ + 1 } # $ is the accumulator\n\nPost-condition (`do ... while`, body runs at least once):\n\n init -> do { $ + 1 } while ($ < 10)\n\nIteration limit (default 10,000):\n\n 0 -> while ($ < 50) do { $ + 1 }\n $items -> fan({ slow($) }, dict[concurrency: 3])\n\nInvalid annotation keys produce a runtime error.\n\n## Break and return\n\n`break` exits a loop or `seq`/`acc` body, returning collected results so far:\n\n list[1,2,3,4,5] -> seq({\n ($ == 3) ? break\n $\n }) # list[1, 2]\n\n`return` exits a block or the script:\n\n 5 => $x\n ($x > 3) ? (\"big\" -> return)\n \"small\" # returns \"big\"\n\n \"done\" -> return # exits script with \"done\"\n\n## Pass\n\n`pass` returns `$` unchanged. Requires pipe context.\n\n cond ? pass ! \"fallback\" # preserve $ when cond is true\n cond ? \"value\" ! pass # preserve $ when cond is false\n \"data\" -> { dict[status: pass] } # dict[status: \"data\"]\n list[1, -2, 3] -> fan({ ($ > 0) ? pass ! 0 }) # list[1, 0, 3]\n\n## Collection operator picker\n\n| Goal | Operator |\n|---|---|\n| Transform each item, sequential | `-> seq({ })` |\n| Transform each item, parallel | `-> fan({ })` |\n| Filter items | `-> filter({ })` |\n| Single result from list | `-> fold(init, { $@ + $ })` |\n| Results plus running accumulator | `-> acc(init, { $@ + $ })` |\n| Stable ascending sort | `-> sort` or `-> sort({ key })` |\n| Loop with state | `-> while (cond) do { }` |\n| Infinite source stream | `iterate(seed, { next })` or `seed -> iterate({ next })` |\n| Suppress rapid stream emissions | `-> debounce(duration)` |\n| Limit to one per interval | `-> throttle(duration)` |\n| Latest at fixed interval | `-> sample(duration)` |\n| Bound body to wall-time limit | `timeout { body }` |\n| Bound body to inactivity limit | `timeout { body }` |\n\n| Operator | Execution | Returns | Catches `break`? |\n|---|---|---|---|\n| `seq` | sequential | all body results | yes |\n| `acc(init, ...)` | sequential | list of accumulator at each step | yes |\n| `fan` | parallel | all body results | no |\n| `filter` | parallel | matching elements only | no |\n| `fold(init, ...)` | sequential | final accumulator only | no |\n| `sort` | eager | sorted list, or `ordered` for dict input | no |\n\n`$@` is the accumulator in `fold` and `acc`. See `stdlib` for `sort` details (key extractor, multi-key tuple projection, descending via `.reverse`).\n\n## Body forms\n\nAll operators accept any callable as the body argument:\n\n -> seq({ $ * 2 }) # block, $ is current element\n -> seq(|x| ($x * 2)) # inline closure\n -> seq($double) # variable closure\n -> seq({ log($) }) # built-in wrapped in a closure\n\nA bare built-in or host name -- seq(log) -- does NOT reference a callable here. In argument position it parses as a zero-arg call log(). Wrap it in a closure.\n\n## Iterating dicts and strings\n\nDict iteration binds `$.key` and `$.value`:\n\n dict[a: 1, b: 2] -> seq({ \"{$.key}={$.value}\" }) # list[\"a=1\", \"b=2\"]\n dict[a: 1, b: 5] -> filter({ $.value > 2 })\n\nString iteration binds `$` to each character:\n\n \"abc\" -> seq({ \"{$}!\" }) # list[\"a!\", \"b!\", \"c!\"]\n \"hello\" -> filter({ $ != \"l\" })\n\n## Loop with multi-field state\n\nUse `while ... do` with `$` as a state dict:\n\n dict[iter: 0, max: 3, text: $input, done: false]\n -> while (!$.done && $.iter < $.max) do {\n $.iter + 1 => $i\n process($.text) => $result\n $result.finished\n ? dict[iter: $i, max: $.max, text: $.text, done: true]\n ! dict[iter: $i, max: $.max, text: $result.text, done: false]\n }\n\n## Iterators\n\nLazy sequences. All collection operators auto-expand iterators.\n\n range(0, 5) -> seq({ $ * 2 }) # list[0, 2, 4, 6, 8]\n repeat(\"x\", 3) -> seq({ $ }) # list[\"x\", \"x\", \"x\"]\n\n`.first()` returns an iterator for any collection:\n\n list[1, 2, 3] -> .first() # iterator at 1\n \"abc\" -> .first() # iterator at \"a\"\n\nIterator protocol (dict with `value`, `done`, `next`):\n\n $it.done # bool: exhausted?\n $it.value # current element\n $it.next() # iterator at next position\n\n## Predicate-gated stream operators: `start_when` / `stop_when`\n\nUse `start_when` and `stop_when` to slice a stream based on a predicate result rather than a fixed index.\n\n| Goal | Operator |\n|---|---|\n| Drop elements until predicate first returns `true`, then yield all remaining | `-> start_when({ cond })` |\n| Yield elements including the first where predicate returns `true`, then stop | `-> stop_when({ cond })` |\n| Keep only elements matching a condition | `-> filter({ cond })` |\n| First n elements by position | `-> take(n)` |\n\n`start_when` vs `filter`: `filter` tests every element independently. `start_when` triggers once and then passes all subsequent elements through, regardless of the predicate.\n\n`stop_when` is inclusive: the element that satisfies the predicate is included in the output.\n\nError contracts (both operators):\n\n| Error | Cause |\n|---|---|\n| `#RILL_R040` | Predicate argument is not callable |\n| `#TYPE_MISMATCH` | Predicate returns a non-`bool` value |\n\nExample:\n\n list[1, 2, 5, 3, 4] -> start_when({ $ > 3 }) # stream[5, 3, 4]\n list[1, 2, 5, 3, 4] -> stop_when({ $ > 3 }) # stream[1, 2, 5]\n\n## `timeout<>` blocks\n\nBound a body to a time limit. On expiry, the block produces an invalid value carrying a timeout atom.\n\n| Form | Expiry atom | Trigger |\n|---|---|---|\n| `timeout { body }` | `#RILL_R082` | Wall-time from block entry |\n| `timeout { body }` | `#RILL_R083` | Inactivity: no stream chunk within duration |\n\n`total` and `idle` are mutually exclusive. The duration must be a `duration` value; non-duration halts with `#INVALID_INPUT`.\n\nExpiry produces a catchable halt. Always wrap in `guard` to catch it:\n\n guard { timeout { $app.fetch($url) } } => $r\n $r ?? \"cached\" # one-liner fallback\n\nDirect `??` on a bare `timeout<>` does NOT catch expiry. Both `total` and `idle` work with `guard`.\n\n## `pass` body forms\n\n`pass` runs a side-effect block and returns the pipe value unchanged. The body form has two surfaces: with and without `<...>` options. Suppression of catchable halts requires `on_error: #IGNORE` explicitly; a bare `pass { body }` does NOT suppress halts.\n\nNote: `pass<>` (empty angle brackets) is a parse error (RILL-P004). Always use `pass { body }` or `pass { body }`.\n\n| Form | Purpose |\n|---|---|\n| `pass` | References current piped value `$`; halts #RILL_R005 if unbound |\n| `pass { body }` | Runs body for side effects; pipe value unchanged; does NOT suppress catchable halts |\n| `pass { body }` | Runs body for side effects; pipe value unchanged; suppresses catchable halts in body |\n| `pass { body }` | Fire-and-forget; body dispatched without blocking; pipe value returned immediately |\n| `pass { body }` | Fire-and-forget; body halt suppressed |\n\n`on_error: #IGNORE` suppresses catchable halts inside the body. Non-catchable halts (`error`, `assert`) and `ControlSignal` (`break`, `return`) still propagate.\n\n`pass` bodies may complete after downstream operators run. Scripts must not depend on body completion order relative to downstream execution.\n\nExample:\n\n 5 -> pass { log($) } # logs 5, yields 5\n 5 -> pass { log($) } # logs 5, yields 5; body halts suppressed\n \"data\" -> pass { audit($) } -> .upper # \"DATA\"\n 42 -> pass { app::log($) } # fire-and-forget; yields 42\n\nDo NOT use `pass { body }` when you need the body result \u2014 the body result is always discarded.\n\nSee `errors` for `assert`, `error`, `guard`, `retry`. See `callables` for closure forms.\n\n---\n\n# rill error handling\n\nAtoms, status sidecars, `guard`, `retry`, vacancy, and recovery patterns.\n\n## Two failure modes\n\n| Failure | Caused by | Caught by |\n|---|---|---|\n| Runtime error (uncatchable) | `error`, `assert`, parameter type mismatch | nothing \u2014 propagates |\n| Access halt (catchable) | Accessing an **invalid value** (status sidecar populated, e.g. failed `:type` assertion, extension `ctx.invalidate`, divide-by-zero (`RILL-R002`), OOB index (`RILL-R042`), missing field (`RILL-R007`), or failed conversion (`RILL-R038`)) | `guard { }`, `retry { }` |\n\n## Assert and error\n\n 5 -> assert ($ > 0) # returns 5\n -1 -> assert ($ > 0) # halts: Assertion failed\n \"\" -> assert !.empty \"Input required\" # halts with custom message\n $val -> assert $:?list \"Expected list\"\n\n error \"Something went wrong\" # halt with message\n \"Operation failed\" -> error # piped form (must be string)\n error \"Status: {$code}\" # interpolation works\n\n## Status sidecar\n\nEvery value carries a status sidecar. Read with `.!`:\n\n| Probe | Returns |\n|---|---|\n| `$v.!` | bool: is this an invalid value? |\n| `$v.!code` | atom: error code (`#ok` on valid values) |\n| `$v.!message` | string: human-readable description |\n| `$v.!provider` | string: component that produced the error |\n| `$v.!trace` | list: trace frames |\n\n`.!` NEVER halts, even on invalid values. Safe to inspect.\n\n## Atoms\n\nInterned identifiers. Type name is `atom`.\n\n #TIMEOUT # atom literal\n #TIMEOUT == #TIMEOUT # true (identity)\n #TIMEOUT -> string # \"TIMEOUT\" (no # sigil)\n \"TIMEOUT\" -> atom # #TIMEOUT\n \"BOGUS\" -> atom # #R001 (unknown names fallback)\n #TIMEOUT:?atom # true\n\nPre-registered atom literals (must start with uppercase letter):\n\n #R001 # unknown atom name\n #R999 # unhandled extension throw\n #TIMEOUT #AUTH #FORBIDDEN #RATE_LIMIT #QUOTA_EXCEEDED\n #UNAVAILABLE #NOT_FOUND #CONFLICT\n #INVALID_INPUT # also: `sort` key extractor returned vacant;\n # negative n for take/skip;\n # n <= 0 for batch/window;\n # step <= 0 for window\n #PROTOCOL #DISPOSED\n #TYPE_MISMATCH # failed `:type` assertion;\n # also: `sort` key extractor mixed types,\n # `sort` `key_fn` not callable,\n # tuple comparison length/type mismatch,\n # start_when/stop_when predicate non-bool\n #IGNORE # sentinel for `pass { body }`\n\n`.!code` reports `#ok` on valid values, but `#ok` is a runtime-only sentinel and is NOT writable as an atom literal in source. Lowercase `#ok` is consumed as a comment by the lexer. Use `.!` to test validity instead.\n\nExtensions register additional atoms at init.\n\n## Guard\n\nRuns the body once. If body halts with a catchable signal, returns the invalid value instead.\n\n \"ok\" => $v\n guard { $v.upper } # \"OK\"\n\n guard { \"x\":number } => $out # catches access halt\n $out.! # true\n $out.!code -> string # \"TYPE_MISMATCH\"\n $out.!message # \"Type assertion failed: expected number, got string\"\n\nFiltered form (catches only matching atoms):\n\n guard {\n $app.fetch($url)\n }\n\n`guard` does NOT catch halts from `error`, `assert`, or a parameter type mismatch. Those propagate. `guard` DOES catch divide-by-zero (`RILL-R002`), out-of-bounds index (`RILL-R042`), missing field access (`RILL-R007`), and failed conversion (`RILL-R038`) \u2014 these behave like any other access halt.\n\n## Retry\n\nRe-enters body up to N times. `limit:` is required and must be a positive integer.\n\n retry {\n $app.fetch($url)\n } => $result\n\n retry {\n $app.fetch($url)\n }\n\nEach failed attempt appends a `guard-caught` trace frame. Bare `retry<3>` is a parse error.\n\n## Vacancy and `??`\n\nA value is **vacant** when empty (`\"\"`, `0`, `false`, `list[]`, `dict[]`) or invalid. `??` returns the fallback when the left side is vacant:\n\n dict[a: 1] => $d\n $d.missing ?? \"default\" # \"default\"\n $d.a ?? \"default\" # 1\n\n guard { \"x\":number } => $out\n $out ?? \"fallback\" # \"fallback\" (invalid is vacant)\n\n## Existence check without halting\n\n`.?field` returns a boolean; never halts. See `types` for type-combined checks like `.?field&string`.\n\n## Timeout error atoms\n\n| Atom | Cause | Recovery |\n|---|---|---|\n| `#RILL_R082` | `timeout` wall-time expired | `guard { timeout { ... } } ?? fallback` |\n| `#RILL_R083` | `timeout` inactivity window expired | `guard { timeout { ... } } ?? fallback` |\n\nExpiry produces a catchable halt. Wrap `timeout<>` in `guard` to catch it as an invalid value; use `??` for a one-liner fallback. Direct `??` on a bare `timeout<>` expression does NOT intercept expiry halts.\n\n guard { timeout { $app.fetch($url) } } => $r\n $r ?? \"cached\"\n\n ($r.!code == #RILL_R082) ? \"timed out\" ! $r\n\n## Recovery patterns\n\nCheck before access:\n\n $v.! ? \"invalid\" ! $v.upper\n\nGuard then inspect:\n\n guard { $v.upper } => $out\n $out.! ? \"failed: {$out.!message}\" ! $out\n\nRetry with fallback:\n\n retry { $app.fetch($url) } => $result\n $result ?? \"fallback\"\n\nBranch on error atom (flat chain, each comparison parenthesized):\n\n guard { $app.fetch($url) } => $result\n ($result.!code == #TIMEOUT) ? \"timed out\"\n ! ($result.!code == #AUTH) ? \"auth failed\"\n ! ($result.!code == #RILL_R082) ? \"total timeout\"\n ! ($result.!code == #RILL_R083) ? \"idle timeout\"\n ! $result.! ? \"error: {$result.!message}\"\n ! $result\n\n---\n\n# rill types\n\nType names, assertions, conversion, parameterized types, dict shapes, type inspection.\n\n## Type names\n\n string number bool list dict ordered\n tuple closure vector iterator any type\n atom datetime duration\n\n## Type assertion `:type`\n\nHalts with `#TYPE_MISMATCH` if value does not match.\n\n 42:number # passes\n \"x\":number # halts\n $val:list(string) # parameterized\n $val -> :number # pipe form\n\n## Type check `:?type`\n\nReturns boolean. Never halts.\n\n 42:?number # true\n \"x\":?number # false\n $val -> :?number # pipe form\n\n## Union types\n\n 42 -> :string|number # passes\n 42:?string|number # true\n \"hello\" => $x:string|number # capture with union\n\n## Parameterized constructors\n\nStructural types with field/element constraints.\n\n list(string) # list of strings\n dict(name: string, age: number) # exact-shape dict\n tuple(number, string) # positional tuple\n ordered(x: number, y: number) # named ordered args\n\n## Asserting dict shapes\n\n $data -> :dict(name: string, age: number)\n $data:?dict(name: string, age: number)\n\nIn closure params (validates input structure):\n\n |d: dict(name: string, age: number)| {\n \"{$d.name} is {$d.age}\"\n } => $format_person\n\n## Property access with type guards\n\n $data.field # dict field\n $data[0], $data[-1] # list index (negative from end)\n tuple[1,\"a\"][1] # \"a\" \u2014 tuple and ordered index by position; ordered also by key\n $data.$key # variable as key\n $data.($i + 1) # computed key\n $data.(a || b) # try keys left to right\n $data.field ?? \"default\" # vacant fallback\n $data.?field # boolean: does field exist?\n $data.?field&string # exists AND is string\n $data.?$key&number # variable existence + type check\n $data.?($expr)&list # computed existence + type check\n\nThe 8 dict method names are reserved and cannot be used as dict keys:\n\n len first empty eq ne keys values entries\n\n dict[len: \"fake\"] # halts: reserved method name 'len'\n dict[label: \"fake\"].len # fine: dict length (non-reserved key)\n\n`.keys`/`.values`/`.entries` and dict iteration visit dict's canonical order (see the Types reference for the exact rule).\n\n## Tuple lexicographic comparison\n\nTuples support `<`, `>`, `<=`, `>=`, `==`, `!=`. Comparison walks elements left to right; the first differing position decides. Each element compares using its own type's protocol. Empty `tuple[]` equals `tuple[]`.\n\n tuple[1, 2] < tuple[1, 3] # true\n tuple[2, 1] > tuple[1, 9] # true\n tuple[1, 2] == tuple[1, 2] # true\n\nIndex a tuple with `[i]` or `.at(i)`; `.1` is a parse error.\n\nDicts have NO comparison protocol. Use tuples for multi-key ordering, including with `sort({ tuple[$.a, $.b] })`.\n\n**Errors:** different-length tuples or differently-typed corresponding elements halt with `#TYPE_MISMATCH`.\n\n## Type conversion `-> type`\n\nExplicit conversion between compatible types. Halts with `RILL-R036` on invalid pairs.\n\n 42 -> string # \"42\"\n \"3.14\" -> number # 3.14\n list[1, 2] -> tuple # tuple[1, 2]\n tuple[1, 2] -> list # list[1, 2]\n ordered[a: 1] -> dict # dict[a: 1]\n\n### Conversion matrix\n\n Source | -> list | -> dict | -> tuple | -> ordered(sig) | -> number | -> string | -> bool\n ---------|---------|---------|----------|-----------------|-----------|-----------|--------\n list | no-op | error | valid | error | error | valid\u00B9 | error\n dict | error | no-op | error | valid | error | valid\u00B9 | error\n tuple | valid | error | no-op | error | error | valid\u00B9 | error\n ordered | error | valid | error | no-op | error | valid\u00B9 | error\n string | error | error | error | error | valid\u00B2 | no-op | valid\u00B3\n number | error | error | error | error | no-op | valid\u00B9 | valid\u2075\n bool | error | error | error | error | valid\u2074 | valid\u00B9 | no-op\n\n \u00B9 formatValue semantics\n \u00B2 parseable strings only; halts with RILL-R038 on failure\n \u00B3 accepts only \"true\" and \"false\"; halts with RILL-R036 otherwise\n \u2074 true \u2192 1, false \u2192 0\n \u2075 0 \u2192 false, 1 \u2192 true; all other values halt with RILL-R036\n\n## Default values in type constructors\n\n dict(a: string, b: string = \"x\")\n ordered(x: number, y: number = 0)\n tuple(string, number = 0)\n\n dict[b: \"b\"] -> dict(b: string, a: string = \"a\") # dict[a: \"a\", b: \"b\"]\n\nOnly `-> type` conversion fills defaults. `:` assertion does NOT hydrate defaults. Nested fields recurse.\n\n## Datetime and duration\n\nConstructed with function-call syntax.\n\n datetime(\"2024-01-15T00:00:00Z\") -> .year # 2024\n datetime(...dict[year: 2024, month: 1, day: 15]) # named components via spread\n now() # current datetime\n duration(0, 0, 0, 25) -> .days # (years, months, days, hours): 1.04\n duration(1) -> .months # 12\n\n## Type inspection `^type`\n\nReturns a type value for runtime inspection.\n\n 42.^type # type value for number\n 42.^type.name # \"number\"\n list[1, 2].^type.name # \"list\"\n list[1, 2].^type.signature # \"list(number)\"\n\nEquality:\n\n $val.^type == list(number) # true if $val is list(number)\n $val.^type == $other.^type # compare structural types\n\n---\n\n# rill callables\n\nClosures, late binding, typed closures, reflection, dispatch operators, extraction, spread, modules.\n\n## Pipe binding rules\n\nWhen `->` targets a callable, the runtime decides how to bind the piped value. Two rules, checked in order:\n\n1. **Explicit `$` (manual placement).** If the immediate argument list contains at least one top-level `$`, every occurrence resolves to the piped value. No auto-prepend.\n2. **Auto-prepend.** If no top-level `$` is found, the piped value is prepended as the first argument.\n\nClosures stop the scan. A `$` inside a closure literal (`{ ... }`) is late-bound when the closure runs per-element. It does NOT count as a top-level `$`. Sub-expressions ARE scanned, so `$` inside `g($)` does count.\n\n**Zero-parameter callables.** When auto-prepend is selected but the callable declares zero parameters, the piped value is silently dropped. The callable runs with no arguments. Execution does not halt.\n\n| Call form | Effective call | Notes |\n|---|---|---|\n| `$val -> fn` | `fn($val)` | Auto-prepend |\n| `$val -> fn(1, 2)` | `fn($val, 1, 2)` | Auto-prepend |\n| `$val -> fn($)` | `fn($val)` | Explicit |\n| `$val -> fn(1, $, 0)` | `fn(1, $val, 0)` | Explicit, middle position |\n| `$val -> fn(1, $, $)` | `fn(1, $val, $val)` | Both `$` resolve to piped value |\n| `$val -> fn(g($))` | `fn(g($val))` | Sub-expr `$` counts |\n| `$list -> filter({ $.active })` | `filter($list, { $.active })` | Closure `$` is late-bound |\n| `$val -> zero_param_fn` | `zero_param_fn()` | Piped value silently dropped |\n\nThis is why `[1,2,3] -> fold(0, { $@ + $ })` works: the list auto-prepends because no top-level `$` appears in `(0, { $@ + $ })`. The `$` inside the closure body is late-bound per element.\n\n## Closure forms\n\nBlock-closures (`{ body }`, implicit `$` parameter):\n\n { $ + 1 } => $inc\n $inc(5) # 6\n 5 -> $inc # 6 (pipe invocation)\n dict[x: { $ * 2 }] # dict value is a closure\n\nExplicit closures (`|params| body`):\n\n |x| ($x + 1) => $inc # named parameter\n |a, b| ($a + $b) => $add # multiple params\n |x = 0| ($x + 1) => $inc_or_one # default value\n |x: number| ($x + 1) => $typed # type annotation\n\n`{ body }` is deferred (closure). `( expr )` is eager.\n\n { $ + 1 } => $fn # closure stored\n ( 5 + 1 ) => $x # 6 stored\n\n## Late binding\n\nClosures capture scope, not values. Variables resolve at call time.\n\n`$` vs named params:\n- Use `$` in inline pipes and loops: `\"hello\" -> { .upper }`\n- Use named params in stored closures: `|x| ($x * 2) => $double`\n- `$` is undefined when a stored closure is called later. Always use named params for reusable closures.\n\n## Zero-param dict closures (methods)\n\n`$` binds to the containing dict.\n\n dict[count: 3, double: ||{ $.count * 2 }] => $obj\n $obj.double # 6\n\n## Typed closures\n\nAnonymous typed closure (`|type|{ body }`, type keyword as param, `$` is type-checked input):\n\n \"hello\" -> |string|{ $ -> .upper } # $ is string, checked at call\n 5 -> |number|{ $ * 2 } # 10\n |number|{ $ * 2 }:number => $double # stored with return type\n 5 -> $double # 10\n \"hi\" -> $double # RILL-R001: parameter type mismatch\n\nAny type from `types` works. Parameterized:\n\n |list(number)|{ $ -> seq({ $ * 2 }) }\n\nReturn type assertion (halts with `#TYPE_MISMATCH` on mismatch):\n\n |x: number| { \"{$x}\" }:string => $fn # asserts string return\n $fn(42) # \"42\" (passes)\n\n |x: number| { $x * 2 }:string => $fn # mismatch halts at call\n $fn(5) # halts: return type mismatch\n\n## Callable reflection\n\n`.^input` and `.^output` work on every callable type.\n\n |x: number, y: string| ($x) => $fn\n $fn.^input # ordered(x: number, y: string)\n $fn.^output # any (no return type declared)\n\n |x: number|{ $x * 2 }:number => $fn2\n $fn2.^output # number\n\n`.^input` returns ordered dict mapping param names to type values. `.^output` returns the declared return type (`any` if undeclared). Works on script closures, built-ins, host functions.\n\nDescription shorthand (bare string in `^(...)` expands to `description: `):\n\n ^(\"Get weather for city\") |city: string| ($city) => $weather\n $weather.^description # \"Get weather for city\"\n\n ^(\"Fetch profile\", cache: true) |id| ($id) => $get_user\n $get_user.^description # \"Fetch profile\"\n $get_user.^cache # true\n\n## Dispatch operators\n\n### Dict dispatch (single key)\n\nPipe a value to a dict to match keys:\n\n $val -> dict[apple: \"fruit\", carrot: \"veg\"] # \"fruit\" if $val is \"apple\"\n $val -> dict[apple: \"fruit\"] ?? \"not found\" # default if no match\n $method -> dict[list[\"GET\",\"HEAD\"]: \"safe\", list[\"POST\",\"PUT\"]: \"unsafe\"] # multi-key\n\nType-aware (key matched by value AND type):\n\n 1 -> dict[1: \"number\", \"1\": \"string\"] # \"number\"\n \"1\" -> dict[1: \"number\", \"1\": \"string\"] # \"string\"\n\n### List dispatch (index)\n\n 0 -> list[\"first\", \"second\"] # \"first\"\n -1 -> list[\"first\", \"second\"] # \"second\"\n 5 -> list[\"a\", \"b\"] ?? \"not found\" # OOB fallback\n\n### Hierarchical dispatch (path)\n\nPipe a list of keys/indexes:\n\n list[\"name\", \"given\"] -> dict[name: dict[given: \"Alice\"]] # \"Alice\"\n list[0, 1] -> list[list[1,2,3], list[4,5,6]] # 2\n list[] -> dict[a: 1] # dict[a: 1] (empty path = unchanged)\n list[\"a\", \"missing\"] -> dict[a: dict[x: 1]] ?? \"default\" # \"default\"\n\nLists require same-type elements. For mixed paths, use property access:\n\n dict[users: list[dict[name: \"Alice\"]]] => $d\n $d.users[0].name # \"Alice\"\n\n## Extraction operators\n\nDestructure (`destruct<>`):\n\n list[1, 2, 3] -> destruct<$a, $b, $c> # $a=1, $b=2, $c=3\n dict[x: 1, y: 2] -> destruct # $a=1, $b=2\n list[1, 2, 3] -> destruct<$first, _, $third> # _ skips\n\nSlice (`slice`):\n\n list[0,1,2,3,4] -> slice<1:3> # list[1, 2]\n list[0,1,2,3,4] -> slice<-2:> # list[3, 4]\n list[0,1,2,3,4] -> slice<::-1> # list[4,3,2,1,0]\n \"hello\" -> slice<1:4> # \"ell\"\n\n## List spread\n\n list[1, 2] => $a\n list[...$a, 3] # list[1, 2, 3]\n list[...$a, ...$b] # concatenate\n list[...($nums -> fan({ $ * 2 }))] # spread expression result\n\n## Argument unpacking\n\n tuple[1, 2, 3] -> $fn(...) # positional spread: $fn(1, 2, 3)\n ordered[a: 10, b: 2] -> $fn(...) # named spread: keys must match param order\n tuple[...$list, 3] -> $fn(...) # spread in tuple then into call\n tuple[1, 2, 3] => $args\n $args -> $fn(...) # spread stored tuple\n ordered[a: 1, b: 2] => $named\n $named -> $fn(...) # spread stored ordered\n\n## Modules\n\n`use` resolves through a host-registered scheme resolver.\n\n use => $g # load module\n $g.hello(\"World\") # call module member\n use # load extension member\n\n`use<>` returns the resolved value (dict, closure, or any rill type). Hosts register resolvers; scripts cannot.\n\nSee `control-flow` for iterators and lazy sequences.\n\n---\n\n# rill stdlib\n\nString, list, dict methods, comparison helpers, and built-in functions.\n\n## String methods\n\n| Method | Description |\n|---|---|\n| `.len` | length |\n| `.empty` | is empty string |\n| `.trim` | remove whitespace |\n| `.upper` | uppercase |\n| `.lower` | lowercase |\n| `.head` | first character |\n| `.tail` | last character |\n| `.at(i)` | character at index |\n| `.first()` | iterator at first character |\n| `.split(sep)` | split into list (default sep: newline) |\n| `.lines` | split on newlines |\n| `.contains(s)` | substring check |\n| `.starts_with(s)` | prefix check |\n| `.ends_with(s)` | suffix check |\n| `.index_of(s)` | first match position (-1 if none) |\n| `.replace(p, r)` | replace first regex match only |\n| `.replace_all(p, r)` | replace all regex matches |\n| `.match(regex)` | first match info: dict with `matched`, `index`, `groups` |\n| `.is_match(regex)` | boolean regex check |\n| `.repeat(n)` | repeat n times |\n| `.pad_start(n, f)` | pad start |\n| `.pad_end(n, f)` | pad end |\n\n`replace` vs `replace_all`:\n\n \"a.b.c\" -> .replace(\"\\\\.\", \"-\") # \"a-b.c\" (first only)\n \"a.b.c\" -> .replace_all(\"\\\\.\", \"-\") # \"a-b-c\" (all)\n\n## List methods\n\n| Method | Description |\n|---|---|\n| `.len` | length |\n| `.empty` | is empty |\n| `.head` | first element |\n| `.tail` | last element |\n| `.first()` | iterator at first element |\n| `.at(i)` | element at index |\n| `.join(sep)` | join elements with separator |\n| `.has(val)` | contains value (deep equality) |\n| `.has_any(list)` | contains any value from candidates |\n| `.has_all(list)` | contains all values from candidates |\n\n## Dict methods\n\n| Method | Description |\n|---|---|\n| `.len` | number of entries |\n| `.empty` | is empty |\n| `.first()` | iterator at first entry |\n| `.keys` | keys as list |\n| `.values` | values as list |\n| `.entries` | list of `tuple[k, v]` pairs |\n\n## Comparison methods\n\nMethod form mirrors operators. Use when piping.\n\n .eq(val) == .ne(val) != .lt(val) < .gt(val) > .le(val) <= .ge(val) >=\n\nExample:\n\n $age -> .ge(18) ? \"adult\" ! \"minor\"\n\n## Built-in functions\n\n| Function | Description |\n|---|---|\n| `log(val)` | print and pass through |\n| `json(val)` | convert to JSON string |\n| `identity(val)` | returns input unchanged |\n| `range(start, end, step?)` | number sequence (iterator) |\n| `repeat(val, count)` | repeat value n times (iterator) |\n| `enumerate(coll)` | lists: `list[dict[index, value]]`; dicts: `list[dict[index, key, value]]` |\n| `chain($fn)` | apply single closure; `chain(val, list[$f, $g])` applies in sequence |\n| `now()` | current datetime |\n| `datetime(...)` | construct datetime (ISO string or named components) |\n| `duration(y, m, d, h)` | construct duration |\n| `sort(list, key_fn?)` | stable ascending sort of a list; returns `list` |\n| `sort(dict, key_fn?)` | stable ascending sort of dict entries; returns `ordered[[key, value]]` |\n\nBuilt-ins are called bare (no `$`):\n\n log(\"hello\") # not $log(\"hello\")\n range(0, 5) -> seq({ $ * 2 })\n\natom is not a function. Convert a string to an atom through the pipe: \"TIMEOUT\" -> atom yields #TIMEOUT. There is no atom(name) call form -- it halts RILL-R006 Unknown function: atom. Unregistered names collapse to the #R001 fallback.\n\n## enumerate example\n\n list[\"a\", \"b\"] -> enumerate -> seq({ \"{$.index}: {$.value}\" })\n # list[\"0: a\", \"1: b\"]\n\n## chain example\n\n chain(5, list[{ $ * 2 }, { $ + 1 }]) # 5 -> 10 -> 11\n\n## sort\n\nStable ascending sort. List sort returns `list`. Dict sort returns `ordered` because rill dicts iterate in a canonical order, so a sorted dict is materialized as ordered key-value entries.\n\n list[3, 1, 2] -> sort # list[1, 2, 3]\n list[\"banana\", \"fig\", \"apple\"] -> sort({ $ -> .len }) # list[\"fig\", \"apple\", \"banana\"]\n\n dict[c: 3, a: 1, b: 2] -> sort # ordered[a: 1, b: 2, c: 3]\n dict[c: 3, a: 1, b: 2] -> sort({ $.value }) # ordered[a: 1, b: 2, c: 3]\n\nMulti-key sort uses `tuple[...]` projection. Tuples compare lexicographically left to right.\n\n list[dict[name: \"alice\", score: 90], dict[name: \"bob\", score: 85], dict[name: \"carol\", score: 90]]\n -> sort({ tuple[$.score, $.name] })\n # list[bob/85, alice/90, carol/90]\n\nDescending order: pipe through `.reverse` after sort. `.reverse` is list-only; dict sort returns `ordered` and does not support `.reverse`.\n\n list[3, 1, 2] -> sort -> .reverse # list[3, 2, 1]\n\n list[3,1,2] -> sort[0] # 1 (index a pipe-target result)\n\nIterators are dicts structurally. `range(0, 5) -> sort` takes the dict path. Materialize first if you want list semantics.\n\n range(0, 5) -> seq({ $ }) -> sort # list[0, 1, 2, 3, 4]\n\nErrors:\n\n| Atom | Cause |\n|---|---|\n| `#TYPE_MISMATCH` | key extractor returns mixed types across elements |\n| `#TYPE_MISMATCH` | `key_fn` argument is not callable |\n| `#INVALID_INPUT` | key extractor returns a vacant value |\n\n## iterate\n\n`iterate(seed, closure): stream of T`\n\nProduces an infinite source stream. Emits `seed` first, then calls `closure` with the current value in `$` to produce the next value. The stream never terminates on its own; bound it externally with `take(n)`, or the iteration ceiling (`RILL_R010`) will halt execution.\n\nPipe form: when piped, the piped value becomes `seed`:\n\n 0 -> iterate({ $ + 1 }) -> take(5) # stream[0, 1, 2, 3, 4]\n iterate(0, { $ + 1 }) -> take(5) # same\n\nFibonacci using dict pair as seed:\n\n iterate(dict[a: 0, b: 1], { dict[a: $.b, b: ($.a + $.b)] }) -> take(8) -> seq({ $.a })\n # list[0, 1, 1, 2, 3, 5, 8, 13]\n\nConsuming >10,000 chunks without bounding halts with `RILL_R010` (non-catchable) at the materializing consumer (e.g., `seq`). `take(n)` clamps silently to MAX_ITER without halting.\n\n## take\n\n`take(list, n: int) -> list[T]`\n\nReturns the first `n` elements. `n < 0` halts with `#INVALID_INPUT`. `n > MAX_ITER` is clamped to `MAX_ITER`. The `list` argument is auto-prepended when piping.\n\n range(1, 11) -> take(5) # list[1, 2, 3, 4, 5]\n list[\"a\", \"b\", \"c\"] -> take(2) # list[\"a\", \"b\"]\n\n## skip\n\n`skip(list, n: int) -> list[T]`\n\nDrops the first `n` elements and returns the remainder. `n < 0` halts with `#INVALID_INPUT`. `n` past the list length returns an empty list. The `list` argument is auto-prepended when piping.\n\n range(1, 6) -> skip(2) # list[3, 4, 5]\n list[\"a\", \"b\"] -> skip(5) # list[]\n\n## cycle\n\n`cycle(list) -> iterator[T]`\n\nReturns an infinite iterator that repeats the input indefinitely. Empty input yields an empty iterator. The bound is enforced at the consumer (e.g., via `take`). The `list` argument is auto-prepended when piping.\n\n [1, 2, 3] -> cycle -> take(6) # list[1, 2, 3, 1, 2, 3]\n\n## batch\n\n`batch(list, n: int, options: dict[drop_partial: bool, idle_flush: duration] = dict[drop_partial: false]) -> stream[list[T]]`\n\nGroups elements into chunks of `n`. The last chunk may be shorter than `n` unless `drop_partial: true`. Pass `idle_flush: duration` to flush the partial buffer early when no new chunk arrives within the given duration.\n\n range(1, 11) -> batch(3) # stream[[1,2,3],[4,5,6],[7,8,9],[10]]\n range(1, 11) -> batch(3, dict[drop_partial: true]) # stream[[1,2,3],[4,5,6],[7,8,9]]\n $stream -> batch(10, dict[idle_flush: duration(0,0,0,0,0,0,500)]) # flush after 500ms idle\n\n`idle_flush` must be a `duration` value; a non-duration value halts with `#TYPE_MISMATCH`. Under synchronous batch execution, `idle_flush` is type-validated but produces no early-flush emissions (async-streaming wire-up deferred).\n\n## debounce\n\n`debounce(stream, duration): stream of T`\n\nStream-only. Suppresses rapid emissions and emits only the latest chunk after a silence window equal to `duration`. When a new chunk arrives before the window expires, the previous candidate is discarded and the timer resets.\n\nPassing a list halts with `#INVALID_INPUT`.\n\nUnder synchronous batch semantics, `debounce` returns the last element (static-clock, all chunks in the same window).\n\n $event_stream -> debounce(duration(0,0,0,0,0,0,200)) # latest after 200ms silence\n\n## throttle\n\n`throttle(stream, duration): stream of T`\n\nStream-only. Limits output to at most one chunk per `duration` interval. The first chunk in each interval passes through; subsequent chunks within that interval are discarded.\n\nPassing a list halts with `#INVALID_INPUT`.\n\nUnder synchronous batch semantics, `throttle` returns the first element.\n\n $event_stream -> throttle(duration(0,0,0,0,0,0,100)) # first per 100ms window\n\n## sample\n\n`sample(stream, duration): stream of T`\n\nStream-only. Emits the latest chunk seen at each fixed `duration` interval. Unlike `debounce`, `sample` emits on a fixed clock. Unlike `throttle`, `sample` emits the most recent chunk rather than the first.\n\nPassing a list halts with `#INVALID_INPUT`.\n\nUnder synchronous batch semantics, `sample` returns the last element.\n\n $sensor_stream -> sample(duration(0,0,0,0,0,0,250)) # latest at 250ms intervals\n\nComparison:\n\n| Operator | Strategy | Trigger |\n|---|---|---|\n| `debounce` | Last of a burst | After `duration` silence |\n| `throttle` | First of an interval | Start of each interval |\n| `sample` | Latest seen | End of each interval |\n\n## window\n\n`window(list, n: int, step: int = n) -> stream[list[T]]`\n\nProduces sliding windows of `n` elements. The default `step` equals `n`, giving non-overlapping windows. `step < n` creates overlapping windows. `step > n` leaves gaps between windows. The `list` argument is auto-prepended when piping.\n\n range(1, 6) -> window(3) # stream[[1,2,3],[4,5]]\n range(1, 6) -> window(3, 1) # stream[[1,2,3],[2,3,4],[3,4,5],[4,5],[5]]\n\n## start_when\n\n`start_when(list, predicate: closure) -> stream[T]`\n\nYields elements starting from the first element where `predicate` returns `true`, then passes all remaining elements through regardless of the predicate. The element that triggers the predicate is included. The `list` argument is auto-prepended when piping.\n\nPredicate must return `bool`. Non-callable predicate halts with `#RILL_R040`. Non-bool return halts with `#TYPE_MISMATCH`.\n\n list[1, 2, 5, 3, 4] -> start_when({ $ > 3 }) # stream[5, 3, 4]\n\n## stop_when\n\n`stop_when(list, predicate: closure) -> stream[T]`\n\nYields elements up to and including the first element where `predicate` returns `true`, then stops. Inclusive of the matching element. The `list` argument is auto-prepended when piping.\n\nPredicate must return `bool`. Non-callable predicate halts with `#RILL_R040`. Non-bool return halts with `#TYPE_MISMATCH`.\n\n list[1, 2, 5, 3, 4] -> stop_when({ $ > 3 }) # stream[1, 2, 5]\n\n## pass body forms\n\nThree distinct surfaces:\n\n`pass` \u2014 bare reference to current `$` in expression position. Halts `#RILL_R005` if `$` is unbound.\n\n`pass { body }` \u2014 pipe stage that runs `body` for side effects. Pipe value flows through unchanged. Halts in `body` propagate.\n\n`pass { body }` \u2014 same as `pass { body }` but suppresses catchable halts that occur inside `body`. Non-catchable halts (`error`, `assert`) and `ControlSignal` (`break`, `return`) still propagate.\n\n`on_error: #IGNORE` is the only recognized option. Empty `pass<>`, unknown option keys, and any other `on_error` value raise `RILL-P004` at parse time.\n\n 5 -> pass { log($) } # logs 5, yields 5; halts in body propagate\n 5 -> pass { log($) } # logs 5, yields 5; body halts suppressed\n 10 -> pass { 1 / 0 } # yields 10; body halt suppressed\n\n---\n\n# rill style\n\nNaming, spacing, line continuations, and idiomatic patterns.\n\n## Naming: snake_case\n\n $user_name, $item_list, $is_valid # variables\n $double_value, $cleanup_text # closures\n dict[first_name: \"x\", last_name: \"y\"] # dict keys\n\n## Spacing rules\n\n| Element | Rule | Example |\n|---|---|---|\n| Operators | space both sides | `5 + 3`, `$x -> .upper`, `\"a\" => $b` |\n| Parentheses | no inner space | `($x + 1)`, `($ > 3) ? \"yes\"` |\n| Braces | space inside | `{ $x + 1 }`, `seq({ $ * 2 })` |\n| Brackets | no inner space | `$list[0]`, `$dict.items[1]` |\n| Literals | space after `,` and `:` | `list[1, 2, 3]`, `dict[name: \"x\", age: 30]` |\n| Keyword + `[` | NO space between | `list[1, 2]` (not `list [1, 2]` \u2014 RILL-P007) |\n| Closures | space after params | `\\|x\\| ($x * 2)`, `\\|a, b\\| { $a + $b }` |\n| Methods | no space before `.` or `(` | `$str.upper()`, `$list.join(\", \")` |\n| Pipes | space both sides | `\"x\" -> .upper -> .len` |\n| Continuations | indent 2 spaces | see below |\n\n## Line continuations\n\nLine-start continuations (begin a new line):\n\n -> => ? ! . .?\n\nTrailing continuations (must end the previous line):\n\n + - * / % == != < > <= >= && ||\n\nOpen delimiters (`(`, `[`, `{`, `|`, `||`) continue across newlines until closed.\n\nValid:\n\n $items\n -> filter({ $.active })\n -> fan({ $.name })\n\n condition\n ? \"yes\"\n ! \"no\"\n\n $.?name&string &&\n !$.name -> .empty\n\nInvalid (RILL-P001 \u2014 `&&` cannot start a line):\n\n $.?name&string\n && !$.name -> .empty\n\n## Idiomatic patterns\n\n### Validate and transform input\n\n $input -> assert $:?string \"Expected string input\"\n $input\n -> .trim\n -> assert !.empty \"Input cannot be empty\"\n -> .split(\",\")\n -> fan({ $.trim })\n -> filter({ !.empty })\n\n### Retry an extension call with fallback\n\n retry { $app.fetch($url) } => $res\n $res ?? \"fallback\"\n\n### Reduce with running state\n\n list[10, 25, 5, 40, 15]\n -> acc(dict[sum: 0, max: 0], {\n $@.sum + $ => $new_sum\n ($ > $@.max) ? $ ! $@.max => $new_max\n dict[sum: $new_sum, max: $new_max]\n })\n # acc emits the running state at each step; last element is final\n\n### Branch on error atom\n\n guard { $app.fetch($url) } => $result\n ($result.!code == #TIMEOUT) ? \"timed out\"\n ! ($result.!code == #AUTH) ? \"auth failed\"\n ! $result.! ? \"error: {$result.!message}\"\n ! $result\n\n## Implicit `$` shorthand\n\nAlways prefer the shorter form.\n\n $.method() -> .method \"x\" -> .upper (not $.upper())\n func($) -> func \"x\" -> log (not log($))\n $fn($) -> $fn 5 -> $double (not $double($))\n\nDon't capture just to continue a chain. Use line continuation. Capture only when the variable is reused.\n\n## When to use `( expr )` vs `{ body }`\n\n| Form | Semantics | Example |\n|---|---|---|\n| `( expr )` | eager \u2014 evaluates immediately | `( 5 + 1 ) => $x` (stores 6) |\n| `{ body }` | deferred \u2014 stores a closure | `{ $ + 1 } => $fn` (stores closure) |\n";