ADR 0055 — Directive integer arguments: positive-integer bounds
- Status: accepted
- Date: 2026-05-22
- Spec target: XTL 0.1
- Affects: grammar.ebnf, language.md § "Top" / "Repeat Right", ADR-0027
Context
grammar.ebnf defines:
top_directive = "@top" , integer ;
repeat_directive = "@repeat" , "right" , [ integer ] ;
integer = digit_seq ;
digit_seq = digit , { digit } ;
The integer production therefore allows 0. The grammar has no
explicit upper bound (which is correct — it is a parsing surface,
not a semantic constraint). But it also has no statement that 0
is semantically invalid.
language.md § "Top" says "Keeps the first N rows after filters and
sorts." For N = 0, the meaning is ambiguous: "the first zero rows"
could mean "produce zero rendered rows" (one reasonable
interpretation) or "the default is no truncation" (another
reasonable interpretation given 0 often means "unset" in CLI
conventions).
language.md § "Repeat Right" says "the column span per repeated
record; when omitted, the column span is 1." A value of 0 is
similarly ambiguous.
The reference impl (src/directive-parser.ts:185-198) rejects both
via n <= 0 and falls through to the generic
xl3/directive/invalid-syntax:
function parseTop(body: string): Directive | null {
const n = parseInt(body, 10);
if (isNaN(n) || n <= 0) return null;
...
}
function parseRepeat(body: string): Directive | null {
const match = body.match(/^right(?:\s+(\d+))?$/i);
if (!match) return null;
const colSpan = match[1] ? parseInt(match[1], 10) : 1;
if (colSpan <= 0) return null;
return { kind: 'repeat', direction: 'right', colSpan };
}
The impl rejects 0, but the spec does not. The grammar
silently allows 0. The error message is the generic
xl3/directive/invalid-syntax rather than a precise
"integer must be ≥ 1" diagnostic.
This is a small surface, but it leaves three rough edges:
@top 0is grammar-legal but impl-rejected — no spec sentence says which is canonical.- The
digit_seqproduction trivially admits00,007, etc. — leading zeros are unstated. - Negative integers are excluded by
digit_seq(no-prefix in integer position), but no normative sentence says so.
Considered Options
A. Grammar-level: replace integer in directive positions with a
new positive_integer production. Pro: parser-level rejection;
no semantic ambiguity. Con: grammar surface grows by one production.
B. Prose-level: keep integer in grammar, add a "MUST be ≥ 1"
sentence to language.md. Pro: minimal grammar change. Con:
"semantics rejects what grammar accepts" is the same shape that
ADR-0027 audited as user-hostile.
C. Status quo (impl checks, spec silent). Worst — silent divergence between grammar and impl.