The specification · Normative text

The host interface

Normative draft. What a host supplies to make the subset mean something and the rule by which each supplied thing is admitted. Rules are F-Host-*. Derived from IntrinsicDef and the three fold predicates (lexicon.ts), createResource/createProperty (runtime.ts), FOLDABLE_AUTHORING_HELPERS and its admission criteria (foldable-helpers.ts), isTrustedExecutableBinding, and findCompositeDefinition, at e4074c17.

The extraction confirmed this list without amendment. The expression layer needed items 3, 4 and 5 and nothing else; items 1, 2 and 6 live in revival and interpretation, which the reference implementation does not yet port.


F-Host-Interface (what a host supplies)

Seven things. The first four are the parameters of the subset, the next two are what the trust rules need, and the last is the rules contract’s.

  1. Entity constructors. Classes whose instances are entities: built by createResource(type, lexicon, attrMap), new (props, attributes?), or createProperty(type, lexicon), new (props). They carry a non-enumerable declarable marker, lexicon, entityType, and for properties kind: "property". Revival constructs them (F-Val-Fate). A constructor holds the props it is given and exposes the attributes attrMap names. It performs no I/O and no network call, reads no file and no environment name, and constructs no entity it was not handed. A host that validates or normalizes props does it in a rule. F-Rule-Pure says the same of rule code and F-Rule-Finding carries the finding to the author.
  2. Attribute exposure. attrMap names the attributes an entity exposes; reading one on a live instance yields an AttrRef bound to that instance (F-Val-Live) and on a name yields the {__attrRef} envelope.
  3. An intrinsic registry ρ: a list of IntrinsicDef.
  4. An authoring-helper allowlist: names a call may fold through as a {__helper} envelope.
  5. A trust set: the package specifiers this build resolved and loaded (arm 1) plus the host’s own module tree (arm 2).
  6. A composite registration form, export const N = Composite(fn, "N") with Composite imported from the host, that makes a project-defined factory interpretable.
  7. Rules: the host’s semantic checks over the folded namespace and the artifact under the contract of rules.md (F-Rule-Supply). A project may supply more as a policy.

In the data-host profile (F-Profile-DataHost, objective.md) a host is a description rather than code: item 3, item 5, and a serialization mapping that says what each envelope becomes in the artifact. Items 1, 2, 4 and 6 need something to invoke and are absent.

F-Host-Registry (the shape of an intrinsic registration)

IntrinsicDef = { name, isTag: boolean, foldsAsCall?: boolean, foldsEagerly?: boolean, … }

F-Host-Admission (when a call may be registered)

A call-form intrinsic, an eager intrinsic, or an authoring helper qualifies only if all hold:

That third clause is the whole correctness argument for every registered call, and it is the same-function principle: revival invokes the function the file’s import names, never a reimplementation (F-Host-NoSubstitution).

Explicitly excluded by chant, with the reason each fails:

F-Host-Closed-vs-Open (why packages are closed and project files are open)

A call into a package folds only two ways:

A call nested inside an expression never folds through a package. A call into a project file folds whenever the callee’s body is itself in the subset with no allowlist.

The asymmetry is the trust boundary. Package code is already loaded and executed by the build before discovery begins; admitting a call into it costs no execution the process was not performing so it is admitted by declaration and verified by registration. Project code is the untrusted input; it is admitted only when it can be evaluated without being executed, folded or interpreted, which a syntactic body check decides and an allowlist could not.

F-Host-NoSubstitution (the function that runs is the one imported)

For every registered name (helper, intrinsic, constructor, composite), revival resolves the name through the folding file’s own import bindings and invokes what it finds (F-Val-Fate, J2 F-Call). A host never substitutes its own implementation for a registered name.

There are two consequences.

This is the CTFE principle (prior-art.md) made a rule.

F-Host-Composite (the registration that admits interpretation)

A project file’s composite is interpretable (rule 2) iff its defining module has export const N = Composite(fn, "N"), where Composite is bound, in that module, to an import of the host’s own, fn is an arrow or function expression, and the name argument is absent or a string literal.

A plain helper that returns a composite is not registered and stays on the invoking path. A host that offers interpretation must define an equivalent registration form. The shape of fn is S-FactoryBody.

F-Host-DataExports (a package’s plain data folds as values)

A named import from an active package resolves to the package’s real export (J2 F-Import). A plain-data export, a pseudo-parameter namespace, an action-constant table, folds as a value; a live Intrinsic instance passes through revival unchanged (F-Val-Live). A namespace import of a package is never resolved (F-Namespace) so nothing is reachable through ns.x from a package: the class or intrinsic has to be reachable through a named import.

F-Host-Trust (what may be imported during a fold)

Two arms, and nothing else:

  1. A specifier that is an active package of this build, or a subpath of one, matched by text against the closed set the build already resolved.
  2. A specifier that resolves to a path inside the host’s own module tree. Text is insufficient here because an untrusted repository controls both its source and its node_modules.

A build with no package list keeps only arm 2. Under ι = isolated, an import outside both arms is F-IsolatedRefusal (J2).

F-Host-Generality (what varies and what does not)

A host may vary the seven items of F-Host-Interface. It may not vary the syntax (grammar.md), the semantics of admitted operators (J1), the module system, the value domain’s shape (values.md), the judgments (J1–J3), and the direction claim (divergence.md). Generality is over host vocabularies (README.md, Scope). A host is one instantiation; chant’s lexicons are the reference instantiation and the reference implementation is meant to carry the interface without any of them.