ADR 0049 - Template-display vs render-output: intentional asymmetry
- Status: informational
- Date: 2026-05-18
- Spec target: XTL 0.x (clarification)
- Affects: authoring UX expectations; cookbook 16, cookbook 17; ADR-0036 (preservation matrix); ADR-0043 (Excel-native preference)
Context
When an author opens an xl3 template directly in Excel — for
editing, review, or sanity-check — they see the template in its
unrendered form. Cells with {{ ... }} placeholders display the
literal placeholder string. This produces three visual surprises
that have been reported as "errors":
- Number-formatted cell holds a string. A cell with
numFmt = "#,##0.00"and value{{ [Amount] }}shows the literal{{ [Amount] }}in the cell (the format does not apply to non-numeric content). - Dashboard sheet formulas error out. A dashboard cell with
=VLOOKUP("key", Data!A:B, 2, FALSE)referencing a placeholder in the Data sheet returns#N/Abecause the lookup against a placeholder string never matches;=Data!B2 + 100returns#VALUE!because string + number fails. - Data validation alerts. A cell with a "must be a number" rule pops a validation alert when the author clicks into the placeholder cell.
These are not bugs in xl3. The render output is correct in every case — the rendered workbook has the right values, the formulas evaluate correctly when Excel recalculates at open time, and data validation rules apply to the substituted values. The "error-looking" display happens only during template authoring, before any render runs.
This ADR settles the contract: the asymmetry is intentional, the recommended response is author convention, and the engine does NOT try to mask it.
Decision
The asymmetry is the contract
The engine guarantees correctness of the rendered output. It does not guarantee that the template, opened in Excel without rendering, displays as a finished workbook.
Concretely, the engine MUST:
- Preserve cell
numFmtso the rendered cell formats correctly. - Preserve formulas verbatim (ADR-0046), including cross-sheet references, so they evaluate against the rendered data at workbook-open time.
- Preserve data validation rules so they apply to substituted values (ADR-0036 §8).
The engine MUST NOT:
- Pre-substitute placeholders with sample values to make the template "look finished." (That would defeat the placeholder as a visual signal — see Rationale below.)
- Maintain a separate "template-view" format and "render" format per cell. (Dual-format adds spec surface and porter cost; the gain is marginal.)
- Rewrite dashboard formulas to be "placeholder-safe." (Authors own dashboard composition.)
Recommended author conventions
Documented in Cookbook 17 — Template-authoring vs rendered preview (this ADR's user-facing companion). Summary:
- Placeholder cells display as text — accept this as intentional signal. The string makes it obvious which cells are template variables and which are static.
- Dashboard formulas referencing placeholder data — wrap
with
IFERROR(...)for clean template-view UX:Pre-render: shows=IFERROR(VLOOKUP("Acme", Data!A:B, 2, FALSE), "—")=IFERROR(AVERAGE(Data!B:B), 0)—or0. Post-render: shows the real value. - Preview the rendered output — use
preview()API,xl3.ioplayground, or a quickconvert(template, sampleData)to verify the dashboard layout. - Data validation on data rows — place validation on the template row only; xl3 propagates it to expanded rows. If the rule rejects placeholder values, accept the template-time alert or relax the rule to "warning" instead of "stop."