Saltar al contenido principal

ADR 0036 - Template feature preservation matrix

  • Status: accepted
  • Date: 2026-05-17
  • Spec target: XTL 0.1
  • Affects: evaluation.md § "Styles and Workbook Structure", ADR-0034 (absorption framework)

Context

evaluation.md § "Styles and Workbook Structure" currently says:

Implementations SHOULD preserve template workbook structure and formatting, including:

  • Cell style
  • Number/date format
  • Font, fill, border, alignment
  • Row height and column width
  • Merged cells where possible
  • Images where possible

This list is intentionally short, but the SHOULD-where-possible phrasing leaves nine common Excel features undefined:

  1. Image anchor behavior across @repeat row expansion
  2. Conditional formatting (rules and ranges)
  3. Chart objects and chart data ranges
  4. Named ranges / defined names
  5. Print area and print titles (repeating rows/columns)
  6. Freeze pane / split
  7. Sheet protection and cell locking
  8. Data validation (dropdowns, range constraints)
  9. Cell comments (notes)

Each of these is something a vendor template can ship with, and a second-language port could silently lose any of them without failing a fixture. Per ADR-0034 Corollary 1, this is an absorption-of-experience moment: name each, choose XTL's answer, pin it.

This ADR bundles all nine into one matrix rather than nine separate ADRs because the underlying decision is the same for most of them — preserve the template's own value, do not auto-extend across @repeat. Bundling keeps the corpus navigable.

Considered Options

For each feature, three classes of answer:

  • Preserve verbatim (P). Template feature survives to the output unchanged. Auto-extension across @repeat is not attempted.
  • Preserve and extend (PE). Template feature survives and the engine adjusts its range/anchor when @repeat expands rows above or through it.
  • Deferred (D). Out of scope for XTL 0.1. Behavior is implementation-defined until a later ADR.

Decision

The per-feature decisions:

#FeatureDecisionRationale
1Images (anchored to ranges)PPreserve the template's image and its anchor range verbatim. @repeat does not shift image anchors. Authors who need images inside a repeat block should design the template so the image sits outside the block (header/footer/sidebar).
2Conditional formattingPPreserve rules; ranges are kept as authored. Auto-extending CF ranges through @repeat is deferred — see Consequences.
3ChartsDDeferred. Chart object preservation depends on ExcelJS chart support (incomplete as of 2026-05); ports based on other libraries vary widely. A future ADR will revisit when Stage 2 conformance reaches charts.
4Named ranges / defined namesPPreserve workbook-scope and sheet-scope named ranges verbatim. References to ranges expanded by @repeat are not auto-adjusted.
5Print area / print titlesPPreserve as authored. Authors who want the print area to cover a repeat-expanded range should set it to the template's full sheet column (e.g., $A:$Z) or to repeating header rows ($1:$1).
6Freeze pane / splitPAlready preserved via views forwarding (see src/excel-document.ts:71). This ADR pins that behavior as normative.
7Sheet protection / cell lockingPPreserve protection state and per-cell locked/hidden flags. Engine-written cells inherit the template cell's lock state, not a synthesized one.
8Data validationPPreserve validation rules at the cell/range level. Ranges are not auto-extended.
9Cell comments (notes)PPreserve verbatim. Comments on cells that get substituted ({{ [Col] }}) survive on the rendered cell.

Why P, not PE, for the items that could be auto-extended

Auto-extension (PE) is conceptually appealing — "the CF rule should cover all @repeat-generated rows" — but the cross-impl cost is high:

  • Each feature has its own range-encoding format in OOXML (CF uses sqref, named ranges use Sheet!$A$1:$B$10, data validation uses sqref, print area uses workbook-scope defined names). Porting nine extension behaviors is nine ports' worth of work.
  • Authors can usually achieve the same effect by anchoring the range with whole-column references ($A:$A) or by using Excel's "include only data rows" patterns. The need for engine-side extension is real but narrow.
  • Silent extension is dangerous — a CF rule that auto-extends might bleed into a footer row the author meant to exclude. Authors are better served by explicit author-side patterns.

XTL 0.1 ships with all of these as P. PE for selected features becomes a candidate for XTL 0.2+ if production users report it as the dominant authoring pain point.

Normative spec addition

evaluation.md § "Styles and Workbook Structure" is amended to state each item explicitly. The current "where possible" phrasing is replaced with concrete rules.

Consequences

  • A port that uses ExcelJS for I/O gets most of these for free (P via load→save round-trip). A port using a different library must verify that each feature in the table survives its load→save cycle and add explicit code paths where it doesn't.
  • Conformance fixture 123 (123-template-feature-preservation) exercises items 1, 2, 4, 5, 6, 7, 8, 9 in Stage 2 OOXML comparison. Item 3 (charts) is excluded per the D decision. Image anchor across @repeat is exercised by fixture 124.
  • Adding "preserve and extend" semantics to any item is a separate future ADR. This ADR does not preclude PE for any item; it pins the 0.1 contract as P.
  • Authors writing templates can rely on the table above as a promise: items marked P will survive to output. Items marked D may or may not.

References

  • ADR-0034 — Relationship to prior-art template engines (this ADR is the first batch absorption following Corollary 1)
  • ADR-0033 — Merged source-table headers (Stage 2 pass-through pattern reused)
  • ADR-0006 — Stage 2 OOXML conformance (where most of these are observed)
  • ADR-0022 — Excel version compatibility (related catalog of what is and isn't portable)
  • evaluation.md § "Styles and Workbook Structure"
  • src/excel-document.ts:65-75 (current cloneWorksheet pass-through path)