CFDL Diagnostics Specification v0.1
Status: Draft
This document defines the canonical diagnostics format, conventions, and error-code taxonomy for CFDL tooling:
- Rust compiler/CLI
- TypeScript editor integration
- Python notebook tooling
Diagnostics must be stable, machine-readable, and suitable for:
- inline editor annotations
- CI test assertions (golden diagnostics)
- user-friendly CLI output
1) Goals
- Actionable: diagnostics should tell the user what happened, where, and what to do.
- Stable codes: error codes must be stable across versions (with deprecation policy).
- Precise locations: diagnostics should include file + span (line/col).
- Non-duplicative: avoid flooding the user with cascading errors; prefer root-cause.
- Composable: same schema for parser, validator, pack validation, and lowering.
2) Diagnostic object (canonical)
2.1 JSON schema (informative)
Tooling SHOULD represent diagnostics in this JSON shape:
{
"code": "E2103_SCHEDULE_OUT_OF_BOUNDS",
"severity": "error",
"message": "Schedule occurrence 2032-01-31 is outside the model timeline (ends 2031-12-31).",
"file": "behavior.cfdl",
"span": { "start_line": 18, "start_col": 7, "end_line": 18, "end_col": 64 },
"path": "contracts[L1].effects.streams[rent].schedule",
"hint": "Update the schedule 'to' date or extend the model time horizon.",
"notes": ["Model timeline: monthly from 2026-01-01 for 72 periods."],
"related": [
{
"message": "Timeline defined here.",
"file": "time.cfdl",
"span": { "start_line": 1, "start_col": 1, "end_line": 1, "end_col": 44 }
}
]
}2.2 Required fields
A diagnostic MUST include:
code(string)severity(enum)message(string)
A diagnostic SHOULD include:
file+spanfor any error tied to source location
2.3 Field definitions
code: stable code (see §6)severity: one oferror,warning,infomessage: concise, user-facing descriptionfile: relative path within model root when applicablespan: source span (1-based line/col)path: optional machine path to IR/AST node for toolinghint: optional “how to fix it” guidancenotes: optional list of additional context linesrelated: optional list of secondary locations
2.4 Span definition
span MUST be:
start_line,start_col,end_line,end_col(all integers ≥ 1)- inclusive start; inclusive end
3) Severity semantics
3.1 error
- Indicates the model cannot be compiled to IR.
- The compiler MUST fail compilation if any
errordiagnostics exist.
3.2 warning
- Indicates a potential issue, ambiguity, or best-practice violation.
- Compilation MAY proceed.
3.3 info
- Non-problem informational messages, e.g., pack hints.
4) Reporting conventions
4.1 Prefer root-cause errors
- When a failure would cascade, report the earliest/root issue and suppress downstream diagnostics.
Example: If time statement is missing, do not additionally report “phase out of bounds”.
4.2 Avoid duplicates
- Same logical issue should produce at most one diagnostic.
4.3 Provide hints for common fixes
- For errors in core DSL structure (missing
term, missingschedule), ahintSHOULD be provided.
4.4 Provide related locations when helpful
- Import cycle errors SHOULD include related module locations.
- Out-of-bounds schedule errors SHOULD include timeline definition location.
5) Parser and recovery guidance
5.1 Parser behavior
- Parser SHOULD attempt recovery to continue parsing and emit multiple diagnostics.
5.2 Recovery strategies
Recommended recovery points:
- End of statement (newline/keyword boundary)
- Block boundary (
})
5.3 Parser diagnostic codes
Parser errors MUST use E0xxx_... codes.
6) Code taxonomy
6.1 Prefixes
E0xxx_*Parse errorsE1xxx_*Module/import/symbol errorsE2xxx_*Validation errors (required fields, schedule bounds)E3xxx_*Type-check / expression contract errorsE4xxx_*Pack-related validation errorsE5xxx_*Lowering/IR emission errorsE6xxx_*Pack lowering-time domain errorsW3xxx_*Warnings (expression inference, extraction failures)I6xxx_*Informational
6.2 Naming conventions
<Prefix><Number>_<CATEGORY>_<DETAIL>
- All caps, underscores.
- Numbers are stable and monotonic within a category.
7) Canonical error codes (v0.1 minimum)
7.1 Parse errors (E0xxx)
E0001_UNEXPECTED_TOKENE0002_UNTERMINATED_STRINGE0003_UNTERMINATED_BLOCK_COMMENTE0004_EXPECTED_TOKENE0005_INVALID_DATE_LITERAL
7.2 Module/import (E12xx)
E1201_IMPORT_CYCLEE1202_IMPORT_NOT_FOUNDE1203_IMPORT_OUTSIDE_MODEL_ROOT
7.3 Global structure (E11xx)
E1101_MISSING_VERSIONE1102_MISSING_MODELE1103_MISSING_TIMEE1104_MULTIPLE_VERSIONE1105_MULTIPLE_MODELE1106_MULTIPLE_TIMEE1107_MULTIPLE_USE_PACKE1108_USE_PACK_NOT_IN_MODEL_FILEE1109_MISSING_ENTITY
7.4 Symbols and references (E13xx)
-
E1001_DUPLICATE_ENTITY -
E1002_DUPLICATE_CONTRACT -
E1003_DUPLICATE_STREAM -
E1004_DUPLICATE_PHASE -
E1005_DUPLICATE_ASSUME -
E1006_DUPLICATE_OPTION -
E1007_DUPLICATE_EVENT -
E1301_UNRESOLVED_ENTITY_REF -
E1302_UNRESOLVED_STREAM_REF -
E1303_UNRESOLVED_CONTRACT_REF -
E1304_UNRESOLVED_OPTION_REF -
E1305_UNRESOLVED_PHASE_REF -
E1306_INVALID_ENTITY_REF_FORMAT— entity ref, stream name, or contract name is not a qualified name with at least two segments (dotted hierarchy).
7.5 Contracts and streams (E20xx/E21xx)
-
E2001_CONTRACT_MISSING_TERM -
E2002_CONTRACT_MISSING_EFFECTS -
E2003_CONTRACT_CURRENCY_REQUIRED -
E2101_STREAM_MISSING_SCHEDULE -
E2102_STREAM_MISSING_AMOUNT -
E2103_SCHEDULE_OUT_OF_BOUNDS -
E2104_SCHEDULE_INVALID_RANGE -
E2105_SCHEDULE_INVALID_DAY_OF_MONTH -
E2106_SCHEDULE_PHASE_NOT_FOUND
7.6 Events and actions (E22xx)
E2201_EVENT_WHEN_NOT_BOOLE2202_STREAM_ACTIVE_NOT_BOOLE2203_ACTION_SET_FIELD_INVALID
7.7 Expressions / typing (E30xx/W30xx)
E3001_EXPR_PARSE_ERRORE3002_EXPR_UNKNOWN_IDENTE3003_EXPR_TYPE_ERRORE3004_EXPR_ILLEGAL_OP
Warnings:
W3001_EXPR_TYPE_UNKNOWNW3002_OBS_REF_EXTRACTION_FAILED
7.8 Pack errors (E4xxx)
E4001_UNKNOWN_TYPE_IDE4002_INVALID_ENTITY_ATTRE4003_INVALID_CONTRACT_TERMSE4004_MISSING_PACK
7.9 Lowering/emission (E5xxx)
E5001_ID_GENERATION_FAILEDE5002_IR_SCHEMA_VALIDATION_FAILEDE5003_IR_EMIT_FAILEDE5004_INVALID_LOWERING_RULEE5005_PHASE_NOT_FOUNDE5006_MISSING_CONTRACT_TERME5007_DUPLICATE_LOWERED_STREAME5008_INVALID_CURVE— duplicate curve name, duplicate point date, or malformed point in acurvestatement
7.10 Pack domain validations (E6xxx–E9xxx)
These diagnostics come from a pack's own validations.toml, evaluated by the
compiler against each contract. They are pack-origin diagnostics and must
include file/span (contract span when a term-level span is unavailable).
Each first-party pack owns a reserved code range; the pack loader rejects a
validations file whose codes fall outside its declared code_prefix.
| Pack | Range | File |
|---|---|---|
| CRE | E6xxx | packs/cre/validations.toml |
| OpCo | E7xxx | packs/opco/validations.toml |
| Energy | E8xxx | packs/energy/validations.toml |
| Credit | E9xxx | packs/credit/validations.toml |
Presence of terms required by a lowering template is not listed here: that
is handled generically for every pack by E5006_MISSING_CONTRACT_TERM.
CRE pack codes:
E6001_CRE_LEASE_MISSING_BASE_RENTE6002_CRE_LEASE_INVALID_TERM_RANGEE6003_CRE_LEASE_UP_MISSING_MONTHSE6010_CRE_EXIT_MISSING_EXIT_CAPE6011_CRE_EXIT_INVALID_EXIT_CAPE6012_CRE_EXIT_MISSING_NOI_VALUEE6020_CRE_OPS_MISSING_AMOUNTE6021_CRE_OPS_INVALID_SCHEDULE
E6004_CRE_LEASE_UP_INVALID_OCCUPANCY is retired: it validated lease-up
occupancy terms that no longer exist. Per §8 the code is never reused.
OpCo pack codes:
E7001_OPCO_LINE_MISSING_AMOUNTE7002_OPCO_LINE_INVALID_SCHEDULEE7003_OPCO_LINE_INVALID_GROWTHE7010_OPCO_WC_MISSING_AMOUNT_OR_RULEE7011_OPCO_WC_INVALID_SCHEDULEE7020_OPCO_EXIT_MISSING_MULTIPLEE7021_OPCO_EXIT_INVALID_MULTIPLEE7022_OPCO_EXIT_MISSING_BASE_VALUEE7023_OPCO_EXIT_INVALID_SCHEDULEE7024_OPCO_EXIT_EBITDA_INVALID_MULTIPLEE7030_OPCO_DEBT_INVALID_AMORTE7031_OPCO_DEBT_INVALID_RATE
Energy pack codes:
E8001_ENERGY_INVALID_DEGRADATIONE8002_ENERGY_INVALID_AVAILABILITYE8003_ENERGY_INVALID_ESCALATIONE8004_ENERGY_INVALID_PRICE_ESCALATIONE8010_ENERGY_INVALID_MACRS_LIFEE8011_ENERGY_INVALID_TAX_RATEE8020_ENERGY_DEBT_INVALID_RATEE8021_ENERGY_DEBT_INVALID_TERM_MONTHSE8022_ENERGY_DEBT_INVALID_PRINCIPAL
Credit pack codes:
E9001_CREDIT_INVALID_BALANCEE9002_CREDIT_INVALID_RATEE9003_CREDIT_INVALID_TERM_MONTHSE9010_CREDIT_INVALID_CPRE9011_CREDIT_INVALID_CDRE9012_CREDIT_INVALID_SEVERITYE9013_CREDIT_INVALID_RECOVERY_LAGE9014_CREDIT_INVALID_SERVICING_FEEE9015_CREDIT_INVALID_PREPAY_PENALTYE9020_CREDIT_RATE_FLOOR_ABOVE_CAP
8) Deprecation and evolution policy
- Do not reuse codes: once assigned, a code is never reused.
- Soft deprecation: a deprecated code may remain emitted for one minor version with a note.
- Hard deprecation: removal only in a major language version.
9) CLI rendering (informative)
CLI tools SHOULD render diagnostics as:
- Single-line summary:
error[E2103_SCHEDULE_OUT_OF_BOUNDS] behavior.cfdl:18:7 Schedule occurrence ...
- Then snippet with caret underline (optional)
- Then hint and notes
10) Golden diagnostics files
For invalid fixtures, store expected diagnostics as:
gold/<fixture>.diag.json
Rules:
- Assert
code,severity,file, andspan. - Messages may be asserted via substring match to allow minor wording changes.