Repository navigation
Make structural Markdown expansion extensible by installed packages #806
Description
Story
As a package author, I want an execution installation to declare and expand
structural Markdown, so a package can add a coordinated parent and child without
adding their names or execution branches to core.
For example, an installed package can make this pair available to the execution
that selected it:
<Deck>
<Panel>First</Panel>
<Panel>Second</Panel>
</Deck>The same declarations drive validation, syntax inspection, and execution.
Without the installation, Deck and Panel are unavailable. Core contains no
branch or reserved-name entry for either form.
Current gap
Ordinary declared Markdown components expand like functions. That is too narrow
for a structural parent, which decides how its direct children are arranged and
when each child is expanded.
Today every structural form is implemented as protected engine syntax. Adding
one requires edits to core's structural table, validation, inspection, and
expansion dispatch. Packages therefore cannot own structural behavior.
Declaration and expansion boundary
ExecutionInstallation.declarations becomes a discriminated catalog containing
the existing Markdown declarations and structural declarations:
type ExecutionDeclaration = MarkdownDeclaration | StructuralDeclaration;A structural declaration describes its public name, origin, authored forms,
props, documentation, and whether it is a parent or a child of another
declaration from the same installation. The installation that contributes the
declaration also supplies its expansion handler. Core captures that association
before installation code or authored content runs.
The existing installation boundary gains the structural expansion handler. The
public contextual ExecutionApi remains unchanged:
interface ExecutionInstallation {
readonly declarations?: readonly ExecutionDeclaration[];
expand?(request: ExpansionRequest): Operation<void>;
install?(): Operation<void>;
}An ExpansionRequest contains the selected declaration facts, evaluated props,
and accepted direct child regions. Canonical core invokes the handler it captured
with the declaration directly; public contextual Execution middleware neither
receives the request nor participates in structural dispatch. The handler is
trusted host code selected before authored content runs, so authority reaches it
as an argument rather than through replaceable context state.
This boundary adds no request authentication, hidden child authority, or second
dispatch protocol. Calling a child region is authority held by the selected
installation handler, not public middleware.
Core evaluates and schema-validates parent and child props before calling the
selected handler. Canonical dispatch selects the handler owned by the captured
declaration. Conflicts and incomplete declaration/handler pairs refuse before
authored content runs.
Explicit child output
Each child region returns its rendered output explicitly:
interface ExpansionChunk {
readonly text: string;
readonly exact: boolean;
}
interface ExpansionRegion {
readonly name: string;
readonly origin: string;
readonly form: InvocationForm;
readonly position?: Readonly<SourcePosition>;
readonly props: Readonly<Record<string, Json>>;
expand(): Operation<Stream<ExpansionChunk, void>>;
}
interface ExpansionRequest {
readonly name: string;
readonly origin: string;
readonly form: InvocationForm;
readonly position?: Readonly<SourcePosition>;
readonly props: Readonly<Record<string, Json>>;
readonly regions: readonly ExpansionRegion[];
}The stream uses existing Effection stream and resource primitives. It preserves
source order and backpressure, and its producer is owned by the handler scope so
cancellation or leaving that scope stops child expansion. Chunks expose rendered
text and the existing exact-output fact; raw segments and expansion engine state
remain internal.
There is no ambient output redirection or default writer for child regions.
Repeated calls to expand() and repeated stream consumption receive no new
at-most-once or single-consumer enforcement in this story.
Scope of this story
This story proves the boundary with a controlled test installation. It does not
extract or integrate terminal-grid behavior. After this lands, #738 rebases onto
it and becomes the first production consumer.
Existing declared Markdown components migrate to the discriminated declaration
catalog without changing their selection, validation, inspection, or execution
behavior. Core's built-in control-flow constructs remain protected and cannot be
claimed by an installation.
Acceptance
- A controlled installation declares a structural parent and child; validation,
syntax inspection, and execution consume the same captured declarations. - Without that installation, its names are unavailable and its handler is not
reached. - Existing declared Markdown components retain their current behavior through
the discriminated catalog. - Parent and child props are evaluated and schema-validated before the selected
handler runs. - The handler receives accepted child regions in source order and can consume a
region's explicit, resource-scoped stream of{ text, exact }chunks. - Focused evidence demonstrates stream backpressure and cancellation ownership
using existing Effection primitives. - Canonical core invokes only the handler captured with the selected structural
declaration; public contextualExecutionmiddleware never receives the
request or its child regions. - Duplicate structural names, broken parent/child declarations, incomplete
declaration/handler pairs, and attempts to claim protected engine syntax fail
before authored content runs. - Existing core structural constructs continue to behave unchanged.
Out of scope
- Terminal/grid package extraction, names, profile wiring, validation, execution,
replay, providers, or teardown. - A general plugin interface, structural registry, family, group, or separate
installation abstraction. - A public contextual
Execution.expandmiddleware operation. - Request authentication, authority tokens, hidden-region dispatch, forgery
protection, or double-delegation enforcement. - Custom diagnostic templates or a diagnostic formatting language.
- Raw AST, recursive expansion functions, mutable accumulators, or engine state
on public requests. - Contextual child-output routing or a default output writer.
- At-most-once expansion or single-consumer stream enforcement.
- Author- or repository-installed structural extensions and shadowing protected
core constructs.
Related work
- Register function components and migrate legacy component handlers #202 delivered ordinary function-component registration.
- Quest: Add interactive grids to executable documents #717 is the interactive-grid Quest.
- ♻️ Converge terminal grids on one immutable state (#730) #738 rebases onto this boundary and supplies its first production structural
installation. - Make executable document grids use
<Grid>and<Pane>#781 owns the final grid package and authored-name rename.
Activity
🚚 Name the declared component MarkdownComponent (#806)
✨ Give installed Markdown components an explicit kind (#806) (#809)
♻️ Give every execution a catalog, and one kind for structural syntax (…
♻️ Read the catalog as the value it now always is (#806)
♻️ Report structural syntax under one kind, and add Structural() (#806)
📝 Describe the two structural shapes, not two kinds (#806)
🐛 Narrow the structural shape before reading its construct (#806)
📝 Say that both structural results share one kind (#806)
✨ Let installations declare structural syntax (#806) (#810)
♻️ Name what an execution supplies while a document expands (#806)
📝 Name what #811 renames, and what the Plan row asserts (#806)
♻️ Name the module for what it resolves (#806)
♻️ Let the resource halt its own producer (#806)
✨ Expand installed structural syntax (#806) (#812)
taras commentedon Sep 13, 2026
Closed by #812