v0.22.0—Bounded nullability checks and practical .NET migration guidance.See what's new

Documentation

Versioning

Version: 2.0.0

This document specifies how Calor semantics are versioned and how version compatibility is managed.


Why Versioning Matters for Agents

Agents will be trained and prompted against specific rules.

When an agent generates Calor code, it relies on specific semantic behaviors:

  • "Overflow traps" (not wraps)
  • "Left-to-right evaluation" (not unspecified)
  • "&& short-circuits" (not eager)

If these rules change between versions without clear versioning:

  1. Agents trained on v1 rules will generate incorrect code on v2 compilers
  2. Prompts that describe v1 behavior will mislead agents on v2
  3. Code that "worked before" will silently break

Stable versioning ensures that agents know exactly which rules apply.


Version Format

Calor semantics versions follow Semantic Versioning 2.0.0:

Plain Text
MAJOR.MINOR.PATCH
  • MAJOR: Breaking semantic changes (agents must be retrained)
  • MINOR: Backward-compatible semantic additions (old code still works)
  • PATCH: Clarifications, bug fixes in semantics (no behavior change)

Current Version

Semantics Version: 2.0.0

Bumped from 1.0.0 for the v0.14 nullability work. This changed the severity of binder diagnostics, not their production CLI routing.

Diagnostic routing correction (2026-09-11)

Error severity in the binder is not the same as production CLI rejection. Historical routing through Calor 0.21: at checked main revision 080ed5a7, Program.Compile used BindingDiagnosticPolicy, which excluded Calor0272 (binding initialization), Calor0273 (return), and Calor0274 (argument). The language server's DocumentState bound directly, so editor diagnostics could differ. Other compiler passes may independently reject the same program.

This historical behavior was not a newly introduced regression. The routing policy and its Program.Compile call were introduced in cc62c4ac, an ancestor of all three release commits below. Each tagged source has the same exclusion and calls the policy from Program.Compile.

Release tagCommitTagged policy / compilation path
v0.14.00e327664Policy / Compile
v0.14.1473cb5e3Policy / Compile
v0.14.21246d8d9Policy / Compile

These are scoped source-history findings, not a claim that every possibly-null program compiles or that every published binary has been independently tested. Calor 0.22's bounded checks (#1082) now activate production Errors at specified initialization, native-return, and resolved method-input boundaries. They cover scalar strings, supported arrays, one-level whitelisted string generic payloads, and identity-proven nominal references. The historical exclusion above is not the current routing policy for those shapes. See the nullability guide for complete examples and mode behavior.

General mutation, member writes, constructor inputs, and outer generic-container enforcement remain excluded; array annotations do not prove every slot initialized. These checks do not establish whole-program non-nullness. The D3/D12/D14 safeguards that demote conditional proofs and retain their runtime guards remain in place. #875 remains open.


Version Declaration

A module declares the semantics version it was written for with a §SEMVER directive, usually the first line of the module body:

Calor
§M{m001:MyModule}
  §SEMVER{2.0.0}
  §F{f001:Main:pub} () -> void
    §E{}
    §R

Syntax

Exactly one spelling is accepted: §SEMVER{MAJOR.MINOR.PATCH} with three numeric parts and nothing else between the braces, for example §SEMVER{2.0.0}. Caret (^2.0.0), range (>=2.0.0 <3.0.0), and shortened (2, 2.0) forms are rejected with Calor0702; so are a leading sign or any whitespace (+2.0.0, { 2.0.0 }), the bracket form §SEMVER[2.0.0], a { not closed on its line, and a second §SEMVER in the same module.

Modules That Declare Nothing

A module without §SEMVER takes the compiler's own version (currently 2.0.0) and gets no diagnostic. The calor hook write-time reminder suggests adding §SEMVER{2.0.0}.


Compatibility Rules

Patch Version Changes (x.y.Z)

Fully compatible. Changes include:

  • Documentation clarifications
  • Specification bug fixes
  • Test additions

Example: 2.0.0 to 2.0.1 is safe.

Minor Version Changes (x.Y.z)

Backward compatible. Changes include:

  • New constructs added
  • New operators added
  • New optional behaviors
  • Extended standard library

Example: Code written for 2.0.0 will compile and run correctly under 2.1.0.

Major Version Changes (X.y.z)

Incompatible by definition. Changes may include:

  • Evaluation order changes
  • Operator precedence changes
  • Type system changes (the 2.0.0 bump changed binder nullability severity, not production CLI routing; see the correction above)
  • Default behavior changes
  • Removed constructs

Example: Code written for 1.x is refused by a 2.x compiler.


Compiler Behavior

The major must match exactly. A module that declares an older major (for example §SEMVER{1.0.0} on the 2.0.0 compiler) is refused rather than quietly read under the newer rules. The error calls for manual review and migration to current semantics before declaring §SEMVER{2.0.0}. Changing the declaration alone is not a migration. There is no legacy Info compilation mode, and Calor0272/0273/0274 are binder/editor diagnostics rather than production CLI rejection gates. See #1084.

Diagnostic Codes

CodeSeverityCondition
Calor0700WarningSame major, declared minor newer than the compiler's (might work)
Calor0701ErrorDeclared major differs from the compiler's — older or newer
Calor0702Error§SEMVER is not MAJOR.MINOR.PATCH, or appears more than once

Compatibility Matrix (2.0.0 compiler)

Module declaresResult
(nothing)Compatible — takes 2.0.0, no diagnostic
2.0.0, 2.0.5Compatible
2.1.0Warning (Calor0700), compiles
1.0.0, 1.9.9, 0.9.0Error (Calor0701) with migration pointer to #1084
3.0.0Error (Calor0701), "upgrade the compiler"
^1.0.0, 2, 2.0, second §SEMVERError (Calor0702)

Version History

Version 2.0.0 (Current)

The v0.14 bump changed binder diagnostic severity. The v0.14.0 promise of legacy Info severity was a future plan, not a shipped mode. The severity helper's lower-major branch does not make older modules compatible. The §SEMVER parser and fail-closed refusal arrived in #1087: that commit is not an ancestor of v0.14.0-v0.14.2, but is an ancestor of v0.15.0 (3bb2601e). Modules declaring 1.x or 0.x are now refused with Calor0701, not compiled in an Info mode. This correction adds no automated semantics migration tool.

Version 1.0.0

Initial formal semantics specification including:

Evaluation Order

  • Left-to-right function argument evaluation
  • Left-to-right binary operator evaluation
  • Short-circuit && and ||

Scoping

  • Lexical scoping with parent chain lookup
  • Inner scope shadows outer
  • Return from nested scope

Numeric Semantics

  • Integer overflow traps by default
  • INT to FLOAT implicit
  • FLOAT to INT explicit

Contracts

  • REQUIRES evaluated before body
  • ENSURES evaluated after body with result binding
  • ContractViolationException with FunctionId

When to Bump Versions

Bump MAJOR When

  • Changing evaluation order of existing constructs
  • Changing default overflow behavior
  • Removing constructs
  • Changing type coercion rules
  • Changing contract semantics

Bump MINOR When

  • Adding new syntax constructs
  • Adding new operators
  • Adding new built-in types
  • Extending pattern matching
  • Adding optional compiler flags

Bump PATCH When

  • Fixing ambiguities in specification
  • Adding test cases
  • Improving documentation
  • Fixing compiler bugs that didn't match spec

Migration Guidance

Upgrading Modules

When upgrading a module to a new semantics version:

  1. Review changelog for breaking changes
  2. Run tests with new compiler version
  3. Update §SEMVER declaration
  4. Test edge cases related to changed semantics

For 1.x to 2.0.0, manually review the current semantics and the module's null-handling choices before changing the declaration to §SEMVER{2.0.0}. Test the migrated code; a version edit or successful compile alone does not establish null safety. Calor0272/0273/0274 can appear in binder/editor diagnostics but do not establish production CLI rejection. Other passes may reject independently. An older-major declaration still produces Calor0701.

Mixed-Version Projects

There is no dual-semantics mode. Every module in a compilation must declare the compiler's major (or declare nothing); a §SEMVER{1.0.0} module is refused until it is migrated.


References