ADR 0015 - Structured error reporting + i18n direction
- Status: accepted
- Date: 2026-05-07
- Spec target: XTL 0.1 draft
- Affects: evaluation.md (errors list), runner-protocol.md
Context
Every spec-defined error today is identified by a stable English
substring carried in Error.message. The conformance corpus relies on
that substring (expected_error: "Source \"X\" is not declared in __sources__"). Hosts that want to localize the error or programmatically
distinguish error categories must scrape the message text.
Two follow-up needs surface this:
- Localization. A Korean operator running a converter sees English error text. Hosts (browser converter, internal portals) want to translate, but only by meaning — they need a stable identifier they can map to a translation table.
- Programmatic dispatch. A SaaS that wraps xl3 may want to
classify failures: parse error vs runtime error, retry-able vs
not, user-facing vs internal. Today every error is a flat
Error.message.
Both needs map onto a single design: assign each spec-defined error a
stable code (xl3/<category>/<short-id>), keep the English message
verbatim for the conformance corpus, and expose the code on the thrown
Error so hosts can read it programmatically.
Considered Options
A. Status quo — substring matching. Cost: localization is fragile; programmatic dispatch is regex-based. Doesn't scale as the error catalog grows.
B. Replace messages with codes. Codes-only, no English text. Cost:
breaks the conformance corpus; readability drops; the operator
running raw xl3 sees xl3/source/undeclared instead of "Source
"X" is not declared in sources".
C. Codes alongside messages (chosen). Each thrown Error carries
a .code property; the message stays English and stays the
conformance contract. Hosts wanting i18n key off .code.
D. Custom error class with structured fields. Beyond code —
category, severity, cause. Cost: spec surface grows; most hosts
just need code. A future ADR can extend.
Decision
Adopt option C. Every spec-defined error throw site SHOULD attach a
stable code to the thrown Error:
const err = new Error(`Source "${name}" is not declared in __sources__`);
(err as any).code = 'xl3/source/undeclared';
throw err;
(The reference impl exposes a small helper xtlError(code, message).)