Modeller
Reference

Template rendering

Render generation plans into immutable proposed output without writing files.

Modeller.Rendering consumes an immutable generation plan and a versioned renderer adapter. It returns complete proposed output artifacts or structured diagnostics; it never changes canonical meaning, the plan, configuration, templates, or the filesystem.

Rendering interface

TemplateRenderer.RenderAsync(request, adapter, cancellationToken) is the public seam. The adapter contract version must match the plan schema before any template executes. Successful output remains ordered exactly as planned and records:

  • logical output path and UTF-8 content;
  • deterministic content digest;
  • plan, pack, template, and input digests; and
  • renderer identity and contract version.

The same pinned plan, templates, renderer version, and limits produce identical bytes and provenance. Output remains a projection: templates and generated C# cannot become semantic authority.

Documented template context

The reference Scriban adapter always exposes artifact_id, logical_path, owner, pack_id, pack_version, template_id, plan_digest, input_digest, and ordered semantic_inputs. Each semantic input contains its id, context_id, and semantic_digest.

A renderer-specific ITemplateGlobalsProvider may add an immutable projection of the semantic input selected while expanding an output recipe. The C# and Python providers both delegate canonical traversal — Entity/Enumeration/Rule/ Behaviour projection, nullability, RuleExpression tree walking, and multi-transition/multi-binding Behaviour handling — to one shared TemplateSemanticProjection, so that logic is implemented once regardless of target language. Each provider then applies only its own naming convention, import formatting, data-type spelling, and boolean-expression joining (&& vs and) on top of that shared projection, adding project settings and a definition view. Templates iterate over that view to produce source; the CLI contains no per-language file-generation logic. No filesystem, environment, clock, network, secret store, or mutable model object is exposed.

Template lookup is by the pinned template identity and digest in the plan. Missing or changed templates fail before producing output for the batch.

Renderer capability resolution

Modeller.Rendering.RendererCapabilityRegistry is the single registered strategy that resolves a validated template pack's (rendererId, rendererVersion, language) to a naming convention, globals provider, and renderer identity — callers never switch on a raw language string. RendererCapabilityRegistry .SupportedRenderers is the renderer allow-list passed into TemplatePackLoader.Load; RendererCapabilityRegistry.Resolve then picks the capability for the validated pack's declared language. A pack whose rendererId/rendererVersion is supported but whose language has no registered capability fails with template-pack.renderer-unsupported before planning — the CLI's WorkspaceGeneration and the Python conformance harness both use this same resolution path, so IRendererAdapter.RendererId/ ContractVersion on the constructed adapter always originate from a validated pack rather than being assembled ad hoc.

Failure and resource limits

Rendering is all-or-nothing. A parse failure, runtime failure, adapter failure, digest mismatch, cancellation, or configured template/output/work limit returns no artifacts. Diagnostics use stable codes and bounded disclosure-safe messages; adapter exception text is never copied into them.

The Child Care reference slice renders a complete deterministic C# Domain Project: project infrastructure plus files for all supported Entities, Enumerations, Rules, and Behaviours. Its regression test changes a Fact in the model while keeping the template bytes unchanged and verifies that the generated C# changes.

The next filesystem step consumes these artifacts through the separate safe application contract; rendering itself performs no writes.

The generation-plan reference documents the only accepted renderer input. CLI generation preview will compose these two interfaces; safe application remains owned by issue #6.

On this page