ADR 0066 — Column-scoped data block
- Status: accepted
- Date: 2026-05-23
- Spec target: XTL 0.1
- Affects: language.md (Data Blocks section, new); evaluation.md (Render Phases); impl (parser, renderer); new error code
Context
Up through 0.7.0 the engine treats the entire width of the data-row
range as part of a single data block. renderer.ts captures every
cell of the block's template rows via row.eachCell({ includeEmpty: true }) regardless of which column the cell sits in, and clones the
captured cells into every expanded row. Rows below the data block
shift down by the splice-insert count across all columns.
This row-wide assumption is not normative — spec/language.md defines
"data block" only in row terms (the rows containing {{[col]}}
expressions). The column scope of a block has been implementation-
defined since 0.1.
The row-wide assumption is a latent bug factory for templates with content beside the data block on the same sheet — the "side summary table" pattern that's common in invoice / 거래명세서 / 정산서 workflows:
row 3: 헤더A 헤더B 헤더C ... 헤더N | 요약 헤더 값
row 4: {{[a]}} {{[b]}} {{[c]}} ... {{[n]}} | 링키지랩 A =SUMIF(...)
row 5: 합계 {{SUM([b])}} | 링키지랩 B =SUMIF(...)
row 6: | 합계 =SUM(Q4:Q5)
Concrete failure modes observed at 0.7.0:
- Issue #46 — silent data loss. OOXML shared-formula owner cells
in P4–S4 (outside the apparent "data" columns A–N) are cloned into
all 858 expanded rows verbatim, producing 858 duplicate owners of
the same
refrange. Excel sees this as corrupt and either drops cells or surfaces a repair dialog. Worked around in 0.7.x withunshareFormula(commitbcbe239), but the root cause is that outside cells were captured-and-cloned at all. - Issue #47 — formula ref staleness. Cells below the data block
but in non-block columns (P5:S14 in the example) get row-wide
shifted by
spliceRowsPreservingMerges. The formula text in those cells (e.g.,=SUM(Q12:Q13)) is preserved verbatim by ExcelJS, so after shift the row references no longer match the cells' new positions. xl3 makes no attempt to rewrite formula refs. - Replication noise. Static side cells (e.g., P4 = '링키지랩 A') get cloned into all expanded rows, producing N identical copies alongside the data — almost never the author's intent.
Two corrective design directions were considered: per-cell formula ref rewriting (matching Excel's "Insert Rows" behavior) or column- scoping the data block. Column-scoping is the simpler, more durable fix — it aligns with Excel's natural intuition (typing in column A doesn't affect column P) and removes the row shift for outside columns entirely, so the ref-staleness problem doesn't arise.