content\n
` | Text segment unchanged — `htmlTags: false` prevents closing |
| F14 | Angle brackets inside code span | `` `a < b` `` before `
` | Already complete — no healing needed |
**Orphaned closing markers (treated as openers):**
| # | Test | Input | Verify |
|---|------|-------|--------|
| F15 | Orphaned bold closer | Text segment starts with `world** more` | Healed to `world** more**` — remend reads the trailing `**` as an opener and appends a closer |
| F16 | Orphaned italic closer | Text segment starts with `text* more` | Healed to `text* more*` |
**Nested and multiple unclosed constructs:**
| # | Test | Input | Verify |
|---|------|-------|--------|
| F17 | Nested bold inside italic | `*hello **world\n
` | Both healed: `*hello **world***` (or equivalent valid nesting) |
| F18 | Multiple unclosed at same boundary | ``**bold `code *italic\n
`` | All three healed independently |
**No-op cases (healing is identity):**
| # | Test | Input | Verify |
|---|------|-------|--------|
| F19 | Complete markdown | `Hello **world** more text` | Unchanged |
| F20 | Empty text segment | `` | Unchanged (empty string) |
| F21 | Text with no markdown constructs | `Hello world` | Unchanged |
| F22 | Already escaped markers | `Hello \*world\n
` | Unchanged — `\*` is not an opener |
**Interaction with interpolation:**
| # | Test | Input | Verify |
|---|------|-------|--------|
| F23 | Unclosed bold containing interpolation | `**{meta.title}\n
` | Bold healed first, then `{meta.title}` interpolated inside healed bold |
| F24 | Interpolation result with markers | `{meta.title}` resolves to `**bold**` | NOT double-healed — markers from interpolation are post-healing |
**Interaction with Content slot:**
| # | Test | Input | Verify |
|---|------|-------|--------|
| F25 | Children with unclosed bold | `
**hello` | Children healed to `**hello**` before substitution into Wrap's body |
| F26 | Component body segment healed independently | Wrap body has `*intro\n
` | Body's text segment healed to `*intro*`, children substituted separately |
**Math blocks (if supported by remend):**
| # | Test | Input | Verify |
|---|------|-------|--------|
| F27 | Unclosed inline math | `$formula\n
` | Healed to `$formula$` |
| F28 | Unclosed display math | `$$formula\n
` | Healed to `$$formula$$` |
### Tier G — Source transform (`eval-transform`)
| # | Test | Verify |
|---|------|--------|
| G1 | `const x = 1` exports | Transformed code appends `env.x = x;` |
| G2 | `let x = 1` exports | Transformed code appends `env.x = x;` |
| G3 | `function f() {}` exports | Transformed code appends `env.f = f;` |
| G4 | `class C {}` exports | Transformed code appends `env.C = C;` |
| G5 | Destructured `const { a, b } = expr` | Both `env.a = a; env.b = b;` appended |
| G6 | Nested declarations not exported | `if (true) { const x = 1 }` — no env write for `x` |
| G7 | Imports from env | Block referencing `port` when env has `port` → preamble: `const { port } = env;` |
| G8 | Only used free variables imported | Block has `port` in env but doesn't reference it → no preamble |
| G9 | Mode detection: `yield` | Top-level `yield*` → mode `"generator"` |
| G10 | Mode detection: `await` | Top-level `await` → mode `"async"` |
| G11 | Mode detection: neither | Plain statements → mode `"sync"` |
| G12 | Mode detection: both yield and await | Top-level yield + await → transform error |
| G13 | Nested yield not counted | `function* inner() { yield 1 }` → mode `"sync"` |
| G14 | Source map generated | `TransformResult.map` is valid V3 source map JSON |
| G15 | `sourceURL` comment appended | Transformed code ends with `//# sourceURL=eval:blockId` |
| G16 | Empty block | Empty source → valid transform with no exports/imports |
### Tier H — Module compilation (`eval-context`)
| # | Test | Verify |
|---|------|--------|
| H1 | Missing-provider diagnostics | `importComponent`, `applyModifiers`, `codeBlock`, and `content` report clear missing-provider errors when no provider is installed |
| H2 | Effection globals available | `sleep`, `spawn`, `createChannel` accessible in compiled block via standard imports |
| H3 | executable.md globals available | `findFreePort`, `Sample`, `when` accessible in compiled block via `@executablemd/core` |
| H5 | `compileBlock` returns generator function | `yield* compileBlock(code, [])` returns a callable generator function |
| H6 | Distinct modules per block | Each `compileBlock` call produces a separate module — no shared state between blocks |
| H7 | `data:` URI encoding | Module source with special characters is correctly URI-encoded |
| H8 | User imports hoisted | User `import` declarations from eval block source appear in generated module |
### Tier I — Middleware conformance (eval modifiers)
| # | Test | Verify |
|---|------|--------|
| I1 | `eval` is terminal | `evalFactory` ignores `next` — never calls it |
| I2 | `eval` returns empty output | `result.output === ""`, `exitCode === 0` |
| I3 | `persist eval` composes | `persist` makes `persistent` answer true, `eval` reads it |
| I4 | `timeout=5s eval` composes | Timeout cancels after 5s if block hangs |
| I5 | `timeout eval` default | Default timeout is 30s |
| I6 | `persist timeout=10s eval` | Three modifiers compose: persist → timeout → eval |
| I7 | `silent eval` | Silent wraps eval — both run, output empty |
### Tier J — Eval journal-entry integration
| # | Test | Verify |
|---|------|--------|
| J1 | `js eval` golden run | Block executes in-process, journal has eval entry |
| J2 | `js eval` repeated run | Block executes again against current inputs |
| J3 | Cross-block bindings | Block 1 exports `port`, block 2 reads `port` from env |
| J4 | Non-serializable binding omitted from journal | Function in env → present in live env, absent from journal |
| J5 | Eval produces no rendered output | Document output excludes eval block content |
| J6 | Generator mode eval | Block with `yield* sleep(100)` executes as generator |
| J7 | Sync mode eval | Block with `const x = 1` executes without yield/await |
### Tier K — Binding environment
| # | Test | Verify |
|---|------|--------|
| K1 | Fresh env per component | Each component expansion gets its own `EvalEnv` |
| K2 | Env shared across blocks in same component | Block 1 and block 2 in same component share `env.values` |
| K3 | `serializeExports` filters non-JSON | Functions, symbols, circular refs excluded |
| K4 | `serializeExports` preserves JSON values | Numbers, strings, objects, arrays round-trip correctly |
| K5 | Eval merges serializable bindings | After the block, `env.values` contains current exports |
| K6 | Component `as` writes to invocation env | Binding is visible to downstream siblings at call site |
| K7 | `
` is not a component boundary | Eval/exec inside `` use parent env/scope and journal normally |
### Tier L — Persist modifier
| # | Test | Verify |
|---|------|--------|
| L1 | `persist eval` retains spawned resource | Resource spawned in block survives block completion |
| L2 | Non-persist eval tears down resource | Resource spawned in block torn down at block end |
| L3 | Persist resource lifetime matches component | Resource torn down when component expansion completes |
| L4 | Persistent flag scoped to chain | `persistent` is `true` only during the persist-wrapped chain |
| L5 | Multiple persist blocks in one component | Each retains its own resources independently |
| L6 | Persist on repeated run | Resource is created and retained again for the current component lifetime |
| L7 | Persist flag does not leak to sibling blocks | Non-persist block after persist block → flag is false |
### Tier M — Timeout modifier
| # | Test | Verify |
|---|------|--------|
| M1 | Block completes within timeout | Result returned normally |
| M2 | Block exceeds timeout | Error thrown: "eval block timed out after 5s" |
| M3 | `parseDuration` handles `ms` | `"500ms"` → 500 |
| M4 | `parseDuration` handles `s` | `"30s"` → 30000 |
| M5 | `parseDuration` handles `m` | `"2m"` → 120000 |
| M6 | Default timeout is 30s | `timeoutFactory(undefined)` → 30000ms |
### Tier O — Eval scope hierarchy
| # | Test | Verify |
|---|------|--------|
| O1 | Eval scope created before durableRun | `resource(useEvalScope())` runs in outer scope, not inside durable execution |
| O2 | Eval scope destroyed on document completion | All retained resources cleaned up when expansion finishes |
### Tier P — Eval binding interpolation
| # | Test | Verify |
|---|------|--------|
| P1 | Bare binding resolves from `env.values` | `{port}` with `env.values.port = 49821` → `"49821"` in content |
| P2 | Bare binding with no env entry left verbatim | `{port}` with no `port` in `env.values` → `"{port}"` unchanged |
| P3 | Bare binding does not match namespaced refs | `{meta.title}` and `{props.name}` not affected by eval binding pass |
| P4 | Multiple bindings in one content | `{host}:{port}` → both substituted |
| P5 | Non-string binding converted via `String()` | `env.values.port = 49821` (number) → `"49821"` |
| P6 | Binding interpolation runs before modifier chain | Resulting `ctx.content` in modifier contains substituted value |
| P7 | Same-run env populated before interpolation | Eval result sets `port`; subsequent block interpolates correctly |
| P8 | Non-serializable binding remains current-run only | Function is usable in the current component expansion and absent from the trace |
### Tier Q — `daemon` modifier
| # | Test | Verify |
|---|------|--------|
| Q1 | `daemon` ignores `next` | `exec` in chain never called — no `durableExec` invocation |
| Q2 | `daemon` produces no journal entry | Journal has no entry for `daemon` block |
| Q3 | `daemon` returns empty output | `result.output === ""`, `exitCode === 0` |
| Q4 | Process forked into eval scope | Process alive during `` expansion |
| Q5 | Process terminated when component scope closes | After expansion, process is not running |
| Q6 | Process terminated on component error | If child expansion throws, process still terminated |
| Q7 | Process terminated on parent cancellation | If parent scope cancelled, process terminated |
| Q8 | Premature exit propagates as error | Process exits during expansion → `daemon()` throws → `ErrorSegment` in output |
| Q9 | `{port}` interpolation in daemon content | Binding from preceding `eval` block substituted into command |
| Q10 | `daemon` without eval scope | No eval scope in scope → clear error |
| Q11 | Modifier chain: `bash daemon exec` | `daemon` is outermost terminal; `exec` present but never called |
| Q12 | Repeated run: daemon starts and stops | Process is spawned and terminated again |
| Q13 | Repeated run: current port used | Eval allocates a current port; daemon binds it |
### Tier R — VM globals
| # | Test | Verify |
|---|------|--------|
| R1 | `findFreePort` accessible in eval block | `yield* findFreePort()` succeeds, returns a number |
| R2 | `findFreePort` returns usable port | Returned port is bindable (no EADDRINUSE) |
| R3 | `findFreePort` called on each run | No port is restored from an earlier trace |
| R4 | `when` accessible in eval block | `yield* when(fn)` retries until fn succeeds |
| R5 | `when` retries on throw | Inner function throws twice, then succeeds → `when` resolves |
| R6 | `when` propagates timeout | Inner function never succeeds → `when` throws after limit |
### Tier S — Provider component pattern (integration)
| # | Test | Verify |
|---|------|--------|
| S1 | Full provider golden run | eval → daemon → when → children → cleanup |
| S2 | Port flows from eval to daemon | `{port}` in daemon content matches `findFreePort()` result |
| S3 | Children can call sample after daemon ready | `sample` calls in children reach daemon endpoint |
| S4 | Daemon terminated after children expand | After `execute` completes, process not running |
| S5 | Provider crash during `when` | Daemon exits before ready → `when` fails → `ErrorSegment` |
| S6 | Provider crash during children | Daemon exits mid-child-expansion → error propagated |
| S7 | Nested providers | Outer + inner provider → both start, inner tears down first |
| S8 | Nested providers, no model | Innermost provider handles sample call |
| S9 | Nested providers, explicit model matching outer | Inner passes through, outer handles |
| S10 | Nested providers, explicit model matching inner | Inner handles regardless of nesting depth |
| S11 | Unmatched model | Chain exhausted → descriptive error naming the model |
| S12 | Repeated provider run | Eval, daemon, readiness, and HTTP calls execute again |
| S13 | Interrupted provider run | Partial diagnostic trace is not accepted as resume input |
| S14 | Multiple provider instances | Two provider siblings → two processes, different ports |
### Tier EO — eval output() function
| # | Test | Verify |
|---|------|--------|
| EO1 | `output()` produces eval block output | Block calling `output("text")` → rendered output contains "text" |
| EO2 | `output()` journaled in entry | `__output` is present in the current eval result |
| EO3 | eval block without `output()` produces no output | Standard eval block → empty output unchanged |
| EO4 | `output()` with multiline content | Multiline string preserved through journal round-trip |
| EO5 | `output()` converts non-string to string | `output(42)` → `"42"` via `String()` coercion |
### Tier RC — renderChildren and render closures
| # | Test | Verify |
|---|------|--------|
| RC1 | `renderChildren()` returns empty for self-closing | Self-closing component → empty string |
| RC2 | `renderChildren()` captures children text | Block component children → rendered text string |
| RC3 | `render()` expands arbitrary markdown | `render("# Hello")` → rendered heading |
| RC4 | `renderChildren(override)` visible + shadows | Override binding resolves in body text/eval; shadows caller value |
| RC5 | `renderChildren(override)` no leak | Override absent from caller env after the render |
| RC6 | `renderChildren(override)` rejects non-object | `null`/array/primitive override → diagnostic |
### Tier Each — `` iteration directive
| # | Test | Verify |
|---|------|--------|
| EA1 | Renders once per item | Body appears once per element; `{item.field}` dotted paths resolve |
| EA2 | Empty array | No output, no error |
| EA3 | Nested `` shadowing | Inner binding shadows; outer intact; neither leaks |
| EA4 | No binding leak | Item binding absent from sibling/parent env after the loop |
| EA5 | Body eval reads the item | Eval block in the body sees the current item |
| EA6 | Segment preservation | Uncaptured loop keeps `ErrorSegment`/`execOutput` (not stringified) |
| EA7 | `as` captures the loop | Full rendered loop stored in binding; no inline output |
| EA8 | Prop contract | Missing/non-array `in`, missing `let`, `let={expr}`, `as={expr}`, reserved-word/unknown props rejected; `as` without env rejected |
| EA9 | Projection | `` through `` resolves `in`, the item, and other caller bindings |
### Tier SC — Sample component (integration)
| # | Test | Verify |
|---|------|--------|
| SC1 | Self-closing with prompt | `` → provider response in output |
| SC2 | With children | `children` → children rendered then sampled |
| SC3 | Model routing | `` → targets specific provider |
| SC4 | No provider | `` outside provider → descriptive error |
| SC5 | Repeated run calls provider | Current provider response is used and journaled |
| SC6 | Self-closing renderChildren returns empty | `` → `renderChildren()` returns empty, prompt used |
### Tier OA — Document Output Api
| # | Test | Verify |
|---|------|--------|
| OA1 | Api creation | `DocumentOutput` Api created with `output` operation |
| OA2 | Core handler is no-op | `output("text")` with no middleware installed → no error, no visible effect |
| OA3 | Middleware intercepts output | `scope.around(DocumentOutput, ...)` receives text in middleware handler |
| OA4 | Middleware transforms text | Middleware modifies text, `next()` receives modified text |
| OA5 | Channel delivery | Channel delivery handler sends text via `yield* channel.send()` |
| OA6 | Consumer collects all chunks | `forEach` consumer collects all emitted chunks in order |
| OA7 | Channel close ends consumer | `channel.close()` causes `forEach` to complete |
| OA8 | Multiple middleware compose | Normalize → terminal → channel: all three run in order |
| OA9 | `ephemeral()` wrapper | `output()` inside durable context produces no journal entry |
| OA10 | execute workflow error surfaces through execution | `execute` workflow error → completion resolves `Err(error)` — `yield* execution` returns the `Result`, never throws |
### Tier WN — Whitespace normalization
| # | Test | Verify |
|---|------|--------|
| WN1 | Trailing whitespace stripped | `"hello \n"` → `"hello\n"` |
| WN2 | Leading newlines collapsed after blank line | Previous write ended with `\n\n`, next starts with `\n\n` → collapsed to `\n` |
| WN3 | Run of 3+ newlines collapsed | `"a\n\n\nb"` → `"a\n\nb"` |
| WN4 | Cross-write tracking | Write 1: `"text\n\n"`, Write 2: `"\n\nmore"` → Write 2 leading newlines collapsed |
| WN5 | Single newline preserved | `"a\nb"` → unchanged |
| WN6 | Empty write | `""` → unchanged, trailing count preserved |
| WN7 | Tab trailing whitespace | `"text\t\n"` → `"text\n"` |
### Tier TF — Terminal ANSI formatting
| # | Test | Verify |
|---|------|--------|
| TF1 | Heading formatted | `"# Title"` → ANSI bold/colored output |
| TF2 | Bold formatted | `"**bold**"` → ANSI bold markers present |
| TF3 | Code block formatted | Fenced code block → syntax-highlighted output |
| TF4 | `async: false` | `marked.parse()` called with `{ async: false }` — no promises |
| TF5 | Middleware composes with normalize | Normalized text passes through terminal formatter |
### Tier SE — Streaming emission
| # | Test | Verify |
|---|------|--------|
| SE1 | Per-segment emission order | Segments emitted in document order |
| SE2 | blockId stability | Per-segment expansion produces same blockIds as batch expansion |
| SE3 | TTY: immediate write | TTY consumer calls `process.stdout.write()` per chunk |
| SE4 | Piped: buffered write | Non-TTY consumer collects chunks, writes at end |
| SE5 | `--raw` flag | No middleware installed — raw text passes through |
| SE6 | Channel close triggers forEach exit | `channel.close()` → consumer's `forEach` completes |
| SE7 | Cancel mid-emission | Scope cancelled between segments → consumer cancelled, no hanging |
| SE8 | Middleware crash | Middleware throws → consumer not orphaned, channel closed |
| SE9 | Cross-boundary communication | `output()` inside durable workflow → channel outside → consumer receives text |
| SE10 | Empty segment | `renderSegment` returns `""` → no `output()` call |
### Tier BC — Block ID counter
| # | Test | Verify |
|---|------|--------|
| BC1 | Counter increments across segments | Block 0 in segment 1, block 1 in segment 2 — IDs are 0, 1 |
| BC2 | Counter stable across runs | Same document structure produces the same block IDs |
| BC3 | Counter threaded through expansion | Nested component expansion uses same counter |
| BC4 | Counter not reset per root segment | Per-segment expansion does not reset counter |
---
## 14. Walked example: diagnostic journal
Given a document that references ``, ``, and an `exec` block:
```console
$ xmd README.md --journal ./run.jsonl
```
The CLI atomically creates `run.jsonl`, executes against the current
filesystem and process environment, and appends journal entries as operations finish:
```
[0] yield root import_component __root__ → { path, content }
[1] yield root import_component A → { path, content }
[2] yield root import_component B → { path, content }
[3] yield root exec "exec:date +%Y" → { exitCode: 0, stdout: "2026\n" }
[4] close root result: { status: "ok", value: "...full rendered output..." }
```
If execution is interrupted, the file may contain a partial trace. An
invocation with the same path fails before the document executes. The user
must preserve the trace for diagnosis or remove it before starting a new run.
---
## 15. Decisions
| # | Decision | Rationale |
|---|----------|-----------|
| 1 | Root document treated as a component | Uniform resolution, parsing, and error handling |
| 2 | All paths are workspace-relative | Diagnostic portability and no absolute-path leakage |
| 3 | Resolution is an Effection Api | Pluggable middleware (search paths, aliases, glob) — runs inside `durableImportComponent` during live execution |
| 4 | `durableImportComponent` is a single journaled operation | Resolve + read in one `createDurableOperation`; one diagnostic journal entry per component |
| 5 | Parsing is runtime | Deterministic from file content, no journal needed |
| 6 | Info string modifiers are a middleware chain | `bash silent exec` — left-to-right wrapping, composable, extensible, compatible with all renderers |
| 7 | Each modifier is a factory that returns `Middleware<[], CodeBlockWorkflow>` | Factory captures params in closure; the block context is delivered contextually via `codeBlock()`/`useCodeBlock()` (§5.5); aligns with Effection v4.1's `Middleware` |
| 8 | `useModifier` registers handlers on the scope | Scope-inherited — child scopes can override parent handlers for their subtree |
| 9 | `exec`/`eval` are terminal handlers, others are wrapping | Terminal handlers ignore `next`; wrapping handlers call `next()` and transform the result |
| 10 | `sample` handler delegates to Sample Api via `durableSample` | Two layers: handler (part of modifier chain) and Api (LLM middleware) — each composable independently |
| 11 | Cycle detection via hide sets, runtime | Deterministic from component graph, no journal |
| 12 | `` is the content slot | Valid JSX, familiar (Astro/React), zero parser changes |
| 13 | `{meta.key}` / `{props.key}` for interpolation | MDX-compatible expression syntax, parsed by regex |
| 16 | Props must be declared in `inputs` frontmatter | Undeclared props are rejected — components are contracts |
| 17 | `inputs` is a canonical draft-07 JSON Schema | The declared input interface is a complete draft-07 schema validated by a shared Ajv instance (strict, `useDefaults`); no bespoke mini-language and no compatibility layer |
| 18 | Requiredness via a parent `required` array | Draft-07 `required` lists the props a caller must supply — no per-field `required` flag, no inferred requiredness |
| 19 | No declared inputs = closed empty-object schema | A component with no `inputs` uses `{ type: object, properties: {}, additionalProperties: false }` and accepts no props |
| 20 | Meta supports optional typed definitions | `meta:` key with JSON Schema subset for components that need schema validation on their own metadata |
| 21 | Prop validation is runtime, not durable | Deterministic from component definition + caller props — no journal entry needed |
| 22 | Components are semantic boundaries for markdown constructs | Bold, italic, links, code spans cannot span across a component or exec block — each text segment is healed independently |
| 23 | Remend runs after scanning, before interpolation | Heals incomplete markdown in text segments; `htmlTags: false` required — boundary scanner owns JSX completeness, remend owns markdown completeness |
| 24 | Healing is runtime, not journaled | Pure function of current text content; no journal entry |
| 25 | `CodeBlockContext` delivered contextually, not as a handler parameter | A scope-local `codeBlock()` provider covers exactly the chain execution; handlers read via `useCodeBlock()`; keeps middleware signature clean `Middleware<[], ...>` |
| 26 | Reusable `Middleware` primitive in `@effectionx/middleware` | Same type as Effection v4.1's Api middleware; `combine()` composes arrays; decoupled from modifier-specific types; originally `src/middleware.ts`, extracted to shared package |
| 27 | `blockId` format: `eval:${componentName ?? "root"}:${index}` | Unique within a document run and stable enough to compare diagnostic traces |
| 28 | Acorn + magic-string for source transform | Acorn provides reliable ES2024 parsing; magic-string preserves source positions for accurate source maps without rebuilding AST |
| 29 | Execution mode auto-detected from AST | No modifier needed — `yield` in body → generator, `await` → async, neither → sync; mixed yield+await is a transform error |
| 30 | `data:` URI module compilation for eval blocks | Eval blocks are compiled into `data:application/typescript,...` URI modules and dynamically imported via `yield* call(() => import(dataUri))`. APIs are standard `import` statements in the generated module, resolved through Deno's import map. `new Function()` is used for expression props (simpler than `data:` URI for single expressions, no module imports needed) |
| 31 | `persist` uses a contextual flag, not direct wrapping | Wrapping the full modifier chain in `evalScope.eval()` hangs because durable effects can't interact with the journal from inside the eval scope's channel processor; instead `persist` makes `persistent` answer true, and `evalFactory` routes only the compiled VM block through `evalScope.eval()` |
| 32 | `evalScope` created before the journaled workflow | The channel processor and eval sender share an ancestor scope |
| 33 | Non-serializable bindings silently omitted from journal | Functions, class instances, and live objects remain in `env.values` during the current run but are absent from the diagnostic trace |
| 34 | Eval blocks produce no rendered output by default | Eval blocks primarily exist for bindings and side effects. The `output()` function (§4.7) optionally produces rendered output; without it, result is `{ output: "", exitCode: 0, stderr: "" }` |
| 35 | `@effectionx/middleware` replaces local `src/middleware.ts` | The middleware primitive was extracted to a shared package for reuse across the monorepo; import paths updated throughout |
| 36 | `daemon` is a terminal modifier that ignores `next` | Process lifetime ≠ command result; `exec` in the chain satisfies the §3.2 detection rule without invoking `durableExec` |
| 37 | `daemon` uses `evalScope`, not the durable run scope | Lifetime matches component expansion — daemon lives for `` and dies with the component, not the whole document run |
| 38 | `daemon` produces no journal entry | The process is an ephemeral resource and starts on every run |
| 39 | Eval binding interpolation uses bare `{name}` syntax | Distinct from `{meta.key}` and `{props.key}` namespaces; local eval bindings are local variables, not namespaced data; regex excludes names containing `.` to avoid conflicts |
| 40 | Eval binding interpolation runs in the expansion engine, not inside modifier factories | Modifiers transform execution results — they are not responsible for preparing source text; one interpolation site in `expandSegments` is consistent with how text segment interpolation already works, and keeps modifier factories free of knowledge about the binding environment |
| 41 | `findFreePort` is a standalone VM global using `node:net` | Port allocation is platform I/O; the function uses Effection's `once` + `race` for event handling and `try/finally` for guaranteed cleanup; exposed in the eval sandbox alongside other Effection globals |
| 42 | `findFreePort` result journaled with its eval block | The port number is a scalar export; no separate journal-entry type is needed |
| 43 | `when` (from `@effectionx/converge`) is the polling VM global | `when` is the exported name from the package; the sandbox already contains it; no rename or addition needed |
| 44 | Provider lifecycle expressed as a component, not an `ExecuteOptions` field | Scope boundary is visible in the document tree; composable — multiple providers nest naturally via structured concurrency; no framework-level lifecycle hooks required |
| 45 | Readiness check is a separate `eval` block, not internal to `daemon` | Auditable — strategy visible in the document; replaceable — different daemons have different readiness signals; composable with `when`'s configurable backoff |
| 46 | Sample middleware reads `baseUrl` from `env.values` | Avoids a dedicated inference server context key; the binding environment is already the shared state carrier for within-component coordination; scope-correct because a fresh environment is provided per component expansion |
| 47 | Each component gets a fresh `EvalEnv` | The component's environment is installed as a scope-local `env` provider around body expansion, so eval blocks within a component share bindings but don't leak into parent or sibling components; critical for provider isolation |
| 48 | `output()` is a plain function, not `yield*` | Output is a synchronous side effect (mutating a ref), not an Effection operation; making it a function keeps the API simple and avoids requiring generator context just to set output text |
| 49 | `__output` stored alongside exports in journal | Avoids a separate journal entry; `__output` is extracted before merging into `env.values` to prevent namespace pollution |
| 50 | `renderChildren`/`render` are closures in `env.values`, not an Api | A Render Api would require middleware installation per component; closures are simpler and capture the expansion context at the injection point; they are non-serializable and silently omitted from the journal |
| 51 | `renderChildren`/`render` install the caller's environment and `parentEvalScope` as scope-local providers | Children are caller-provided content and expand in the caller's scope context; the component's `childEvalScope` sequential channel is for its own `persist eval` blocks, not for expanding caller content; children may create resources (nested components, daemons) but their lifecycle is bound by their place in the expansion tree; installing providers inside the closure ensures the correct context is visible regardless of which task it runs in |
| 52 | `durableSample` routes through `EvalScope` | Sample Api middleware installed by `persist eval` blocks (e.g., `LlamafileProvider`'s `Sample.around()`) lives in the eval scope's task hierarchy; routing through `evalScope.eval()` ensures the middleware chain is found |
| 53 | Sample component calls `Sample.operations.sample()` directly | The enclosing eval operation journals the complete block result |
| 54 | Sample component props default to empty string, not undefined | `validateProps` omits optional props with no default from `env.values`, causing `ReferenceError` in eval blocks; empty-string defaults ensure the variables exist; `model \|\| undefined` converts empty to undefined for routing semantics |
| 55 | `daemon()` uses `shell: true` | Matches `bash exec` block semantics — the same command string passed to `bash -c` is passed to the shell; handles shell expansions and PATH lookups correctly |
| 56 | Provider installs its own middleware, not a global `useLlamafileSample()` | A single global handler installed before `execute()` would execute in the outer scope at call time, where the binding environment has no `baseUrl`; middleware must close over `baseUrl` and `model` at the moment the provider becomes active |
| 57 | Routing key is `model`, not a separate `name` prop | Model identity is the natural key — it unifies "which server to route to" with "which model to request"; a separate `name` prop would require keeping two values in sync with no added expressiveness |
| 58 | `context.model === undefined` routes to innermost provider | Omitting a model is the common case for single-provider documents; innermost-wins matches how middleware chains work — handlers installed later sit higher in the chain and are traversed first |
| 59 | `callLlamafile()` is a standard import in generated eval modules | Provider components are markdown files — eval blocks are compiled into `data:` URI modules that import executable.md globals from `@executablemd/core`; functions like `callLlamafile`, `callOllama`, `callAnthropic`, `Sample`, `findFreePort`, and `useContent` are available via this import |
| 60 | Props pre-populated into `env.values` at component invocation | Code block content uses bare `{name}` binding interpolation from `env.values`; props must enter `env.values` at invocation time to be accessible in code blocks; consistent with how eval bindings work |
| 61 | `callLlamafile()` uses `@effectionx/fetch` | The HTTP call is an Effection operation executed once per document run |
| 62 | `LlamafileProvider.md` hardcodes `/health` endpoint | All major llamafile/llama.cpp-compatible servers use `/health`; the hardcoded path covers the supported targets |
| 63 | `stdio: "inherit"` is the default for `daemon()` | During development, seeing server logs in the terminal is valuable; production deployments can pass `stdio: "ignore"`; the executable.md `daemonFactory` passes no stdio option, defaulting to `"inherit"` |
| 64 | `DocumentOutput` Api with single `output` operation | Extensible to progress/diagnostics; middleware-composable via `scope.around`; single Api surface for all output concerns |
| 65 | Whitespace normalization is middleware, not post-processing | Stateful across calls; composes with other middleware; can be disabled via `--raw`; mutable closure state scoped per `useNormalizedOutput()` call |
| 66 | Terminal formatting is middleware, not a separate renderer | Composes with normalization; conditional on TTY; disabled for piped output; uses `marked-terminal` with `async: false` |
| 67 | Channel-based delivery, not direct `process.stdout.write` | Decouples production from consumption; enables buffered collection for piped output; consumer task lifetime tied to document run scope; `channel.close()` in `finally` block guarantees consumer exits cleanly |
| 68 | Per-root-segment emission for roots without `