Changelog
All notable changes to Calor, organized by release.
[Unreleased]
[0.13.2] - 2026-08-12
Hardening release. The compiler's control-flow and dataflow foundation is rebuilt on explicit semantics, and the build and release chain becomes hermetic and supply-chain verified.
0.13.1 was tagged but never published. Four publish attempts failed and nothing was ever pushed to nuget.org under that version. Rather than publish it from a main that had since gained a compiler-internals rewrite it did not describe, 0.13.1 is abandoned and its contents ship here, described accurately.
Changed
- Z3 translation aligned with executable C# semantics. Integral literal width and signedness survive translation, and C# numeric promotions apply across arithmetic, comparison, equality, shifts and overflow. Operations with no executable C# semantics stay fail-closed rather than approximated. Translator semantics are versioned in proof results and cache validity, so existing verification caches are invalidated by this release and proofs are re-established under the corrected semantics.
- CFG and dataflow rebuilt around explicit semantics. Control flow is constructed from explicit terminators and typed edges rather than positional inference; loop, exception, catch, finally, using, return, throw, break and continue route structurally. Dataflow fails explicitly rather than silently on non-convergence, and initialization, liveness and reaching-definitions analyses are symbol-keyed and semantically ordered.
- Builds and releases are hermetic and supply-chain verified. Z3 is restored by an explicit bootstrap instead of downloaded mid-build, and every supported binary is verified against committed SHA-256 and byte-size pins before compilation. NuGet versions are centralized with committed lock files and locked restores, alongside offline build/test/pack, corrupt-asset, lock-mismatch and runtime-load gates, SPDX SBOMs and SLSA-style provenance.
- Round-trip verification is failure-safe. Conversion runs in lossless mode and validates generated C# before publication, failing closed rather than reporting success on build, process or coverage failures. Excluded and failed items stay visible in reports.
Fixed
- Z3 downloads survive a real outage. Every fetch path used
--retry 5 --retry-delay 3— and percurl(1), setting--retry-delaydisables exponential backoff, so the flag that reads as hardening pinned retries to a flat 3s and gave up in about fifteen seconds, shorter than a routine CDN blip. Backoff is restored across every fetch site, including the publish path, and the Windows path — which had no retry at all — now backs off too. - MCP tools no longer refuse work because their host is using memory. The heavy-tool admission gate measured whole-process memory and applied everywhere, so a handler embedded in someone else's process charged that process's memory to the next tool call and refused it. The gate now applies only to the stdio server, which owns its process.
Removed
- VS Code extension support is withdrawn. The extension tree, VSIX release assets, Marketplace publishing, and the single-file publish guard are removed. The language server is unaffected:
calor lspspeaks standard LSP over stdio and works with any LSP-capable editor.
[0.13.1] - 2026-08-12
Completes the 0.13 project-model program: the persistent index and calor query ship — the item deferred three times in 0.13 — and four release gates close.
Not 0.14. The "Null-Safe .NET" content (metadata-backed .NET binding, typed semantics, non-nullable reference types, the 2.0.0 self-migration) remains unbuilt and will ship as §SEMVER{2.0.0} when it does.
Added
- Persistent project index and
calor query.calor index buildwrites a versioned index underobj/calor/;calor index statussays whether it can still be trusted.calor queryanswers six facets:symbol,callers,callees,impact,contracts,assumptions. Two rules are enforced rather than documented — a stale index never answers, and every answer carries its residual, naming what could not be resolved rather than quietly omitting it. calor rename— rename addressed by symbol identity rather than text, refusing rather than guessing on ambiguity, stale sources, collisions, and declarations split across files.- Dogfood utility — a real in-repo tool whose only source is Calor, built and run by CI.
- Four release gates closed: full-vs-incremental diagnostic identity, index/query correctness, rename (with an apply-recompile-and-run behaviour oracle), and the performance envelope (index build 0.40s against a 30s budget; warm queries under a millisecond against 500ms).
- Exact-span LSP refactoring — definition, references, and rename distinguish overloads, shadowed locals and fields, and same-spelled symbols across files.
Fixed
- Module-qualified cross-module calls resolve. Writing
§C{Module.Function}previously gave a worse result than the bare form — it was treated as an unknown external call and forbidden inside a pure function even when the callee was pure. - Generated C# is guaranteed Roslyn-valid; formatting is lossless and atomic.
[0.13.0] - 2026-08-11
The "Trustworthy Project Model" release. Headline: the structural-binding rebuild is complete — all 60 accepted expression classes bind structurally (the analysis-incomplete instrument is retired because nothing is incomplete), with stable symbol identities, full-signature overload resolution, exhaustive checker traversals, a resolved call graph, and LSP rename/references/cross-file resolution on top.
Release-gate scorecard, stated plainly
- Green, measured: binding totality (zero incomplete on both measurement corpora, ratcheted in CI); the verifier-vs-runtime differential gate (65/65 modeled forms, 1,170/1,170 cases, zero mismatches, CI-blocking); the migration fixture registry (enforcing).
- Not met, disclosed: the full-vs-incremental identity harness and the rename harness were registered but never built — they ship unmet and are the top of 0.13.x.
- Deferred, named: the persistent index /
calor querydid not ship — the fourth deferral of an item the plan pre-committed not to defer again. First index work item in 0.13.x.
Added
- Verifier-vs-runtime differential gate: 1,170 deterministic cases across all 65 frozen modeled forms × contract positions × nesting depths × polarity, with a compile-and-execute oracle. CI blocks on zero mismatches.
- Structural binding for every expression class, with an authoritative dispatch table, reflection completeness tests, and a two-leg corpus ratchet that makes coverage regression a CI failure.
- Stable SymbolIds and exact identifier spans consumed by the LSP (rename, references, cross-file resolution).
- Top-level overload sets: duplicate signatures, ambiguity, and no-match are explicit diagnostics — a second same-name declaration no longer silently vanishes.
Changed
- Proof-based guard elision is now opt-in (
--elide-proven-guards): verification verdicts are diagnostic by default; aProvenresult keeps its runtime guard unless you opt in. The differential gate that would justify flipping the default is now built and green; the flip is a deliberate next-cycle decision. - Verification cache keys are exhaustive and semantics-versioned: content-hashed over the modeled surface, namespaced by compiler-semantics version and solver budget, with collision-unsafe keys refused outright.
- MSBuild incremental builds fingerprint every diagnostics-affecting input, including referenced assemblies and IL-analysis inputs — flipping any of them against a warm cache forces a recompile.
Removed
- The
osx-x64Z3 native is no longer shipped. Upstream ships an arm64 binary under the x64 label, so Intel Macs installed successfully and silently lost verification — no honest asset exists to ship. Intel macOS is unsupported for verification (compilation is unaffected; Z3-dependent features report "Z3 unavailable" loudly). A native arch-vs-RID assertion in the packaging workflow prevents any recurrence.
Known channel state
- The VS Code Marketplace remains at v0.3.8 (expired publish token, maintainer-only); this release does not change that.
[0.12.1] - 2026-08-07
A packaging release. v0.12.0 was tagged but never installable — both publish workflows failed, so nuget.org continued to serve 0.10.0 and the VS Code marketplace continued to serve 0.3.8. Nothing in the language, compiler, or verifier changed here.
Fixed
- The VS Code extension builds again — though it still did not publish. The build failure below is fixed and all six platform packages are produced, but the publish step then failed on an expired marketplace token, so the marketplace remains at
0.3.8. That token, not the build, is why the extension has failed to publish on every release since v0.4.0 — the last successful publish was v0.3.8. The language server is packed as a single file, which promotesAssembly.Locationto a build error. Fixed at both sites — one justified suppression where the empty location is a supported and already-guarded input, and one switch to the single-file-safeRuntimeEnvironment.GetRuntimeDirectory(), since the old expression would have silently emptied the framework probe root used by IL effect analysis. - The NuGet publish no longer fails its own checksum gate. The gate was right — the pinned Z3 binaries release had been republished underneath its manifest. Two underlying defects are fixed rather than papered over by rehashing the live assets: the managed
Microsoft.Z3.dllwas selected withfind | head -1across all build artifacts, andlinux-arm64was built from source despite upstream publishing a binary for it. Both now come from checksum-verified upstream archives, so the published assets are reproducible. - The shipped Z3 managed wrapper is now upstream's Release build. Because of that selection race, released packages had been carrying a Debug assembly compiled on a CI runner, with the runner's absolute build path embedded in it.
- Z3 now loads on ARM64. Upstream's Windows x64 archive ships an AMD64-marked wrapper that cannot load in an arm64 process, and both download scripts had designated it. This affected
linux-arm64andwin-arm64; it stayed hidden because x64 CI cannot observe it. - Republishing the shared Z3 binaries is now deliberate. The build workflow no longer runs on push — which is what invalidated the pin originally, since the commit that introduced the manifest re-triggered the workflow and republished every asset a day later.
Added
- CI now exercises both release-only paths. Neither failure was catchable before release day, because the single-file publish and the binary pins were only ever exercised while publishing. The test suite now runs the same single-file publish the extension build uses, and a scheduled check verifies the binary pins daily against both the project's release and the upstream archives.
[0.12.0] - 2026-08-06
The soundness release. This entry covers the v0.11 range as well — there is no v0.11.0 tag; the maintainer folded v0.11 forward, so everything below ships together.
Benchmark and release gates
- 217-program micro-benchmark: overall 1.32x Calor/C#, with Calor ahead in seven of eight metrics. Comprehension is 1.84x, error detection 1.49x, token economics 1.42x, and information density 0.98x (C# wins).
- Statistics caveat: all 30 runs are identical deterministic static analyses. Zero-width confidence intervals and the reported p-values describe no run-to-run variance; they do not measure uncertainty over the corpus.
- These numbers are not the release gates. PP-A1 passed all nine adoption items. PP-W5 recorded a 1.0016 point estimate as "no large tax detected", explicitly not a proof of parity.
Six distinct false-proof vectors were closed — cases where a proof deleted a runtime check that would have failed. Enumerated so the count is checkable: (1) D4 non-ordinal string comparison modes; (2) D4 bare StartsWith/EndsWith/IndexOf, which use the current culture in .NET and so diverge with no mode argument present to signal it; (3) D3, Z3 strings are null-free; (4) D12, Z3 models strings as UTF-8 bytes where .NET counts UTF-16 units; (5) D14, array and user-type sorts are total and non-null; (6) the third $length mint site, which the D14 fix's own first cut missed.
Items (1), (2), (3), (4) and the array half of (5) carry a recorded calor run versus calor run --verify reproduction. Only the user-type half of (5) rests on inspection of the encoding; item (6) is not reachable from --verify at all — it served a false proof to agents through the MCP refine tool, which is how it surfaced. That is six closures, not six review rounds, and the number of vectors still unfound is not knowable and is not claimed to be zero.
What closed the class was a change of mechanism, not a better enumeration. Hand-enumeration was tried at three levels — divergence rows, then Z3 sorts, then mint sites — and missed something at every one. Proofs carried by a sort Z3 models as total are now demoted to Assumed, which never elides, so the class closes by construction.
Added
calor import <package>generates effect manifests from real assemblies in three tiers — IL-derived, curated, and unresolved, which is surfaced loudly and excluded rather than defaulted to pure. Nothing is ever emitted asverified. Validated on Serilog and MediatR.calor review-packetleads with the unproven remainder: seven-status counts, assumption lists, vacuity flags, counterexamples, and per-module interop/waiver fractions with waiver disclosure on the first line.- Adoption playbook and a tested eject path — an 11-test suite that compiles and executes ejected C# to pin exactly what survives leaving Calor.
- Effect soundness (WS-W2). Invoking a delegate held in a value is now an error rather than an assumed-pure no-op; effect variance is checked on both the override and interface legs; interop is
Assumedand propagates transitively; the known-pure list no longer contains mutators; and both silent=> Emptycatch-alls are replaced by exhaustive switches.--enforce-effectsdefaults on. - A self-contained
Calor.Sdkpackage. The SDK carries its build task, compiler/runtime dependency closure, and per-RID Z3 natives. CI installs the packed SDK into a project with no project references and requires a real Z3 counterexample from the MSBuild task. - Telemetry is opt-in and metadata-only. Default invocations send nothing. Enabled telemetry excludes source, paths, diagnostic/exception text, stack traces, hostnames, help queries, and content hashes.
Changed
- Postcondition elision is withdrawn for any signature naming an array or a non-primitive type. Z3's array and user-type sorts are total and non-null; .NET's are nullable references. Coarse on purpose — being wrong in the narrow direction deletes a runtime check, being wrong in the broad direction costs an optimization. Contract proving and reporting are unchanged.
- The type checker is on by default, which required first fixing the checker: turning it on produced 92 test failures, every one of them a working program the checker refused. They trace to roughly eight defect classes —
charalone accounts for 37 of the 92 — coveringobject,decimal, every sized integer, arrays, string concatenation and static member access.--no-type-checkopts out onbuild;CALOR_NO_TYPE_CHECK=1opts out everywhere, includingrun,test,watchand the MSBuild task inside the SDK. - Conversion no longer substitutes silently. Unknown operators, patterns, and compound assignments escalate to loud interop blocks instead of quietly becoming something else.
- Conversion success is loss-aware. Generated output is compile-validated; the success line appears only for zero-loss output, while text and JSON name every semantic loss and preserved interop member.
Fixed
- A quantified-contract lowering bug that discarded implication antecedents was fixed before release. It demonstrated that encoding soundness and runtime lowering soundness are separate surfaces.
- Direct self-recursion no longer fails as an unknown effect target.
calor_refineno longer reports success after a failed compile.- Z3-backed CI tests can no longer silently turn green by skipping when the native solver is unavailable.
- The VS Code package now includes
vscode-languageclient, fixing its long-standing activation defect. The Marketplace publish itself did not succeed; the listing remains at v0.3.8.
Known limitations shipping with this release
All pre-existing rather than regressions: §MT contract violations report the wrong function id; a contract call carrying a keyword argument crashes the translator instead of diagnosing it; str is not yet non-nullable at the binder, which is what would let the string demotion be lifted; and IL-analysis inputs are not all included in the MSBuild task's warm-cache options hash.
[0.10.0] - 2026-07-30
The Guarantees release: every verification verdict an agent sees is now sound, honestly statused, and provenance-aware — and the upgrade is measured. On a paired A/B probe epoch, all three seeded contract defects moved from runtime exceptions to build-time refutations under the new verify gate, with zero catch regression and zero contract weakening across 30 eligible runs.
Added
- Sound result binding (#807 closed). Result-referencing postconditions are checked against the encoded function body (SSA-style substitution over immutable
§Bchains, guard-clause branching, and value returns); bodies outside the encodable surface report honestunsupported— never a refutation against an unconstrainedresult. - Seven-status verdict vocabulary.
assumed(holds conditionally on a named assumption set — division side conditions are the first producer; never elides runtime checks) andunavailable(no solver present) join the five existing statuses; vacuous proofs carry avacuousflag and keep their runtime checks. Envelope schema 2.0. - Positive modeled-forms whitelist.
unsupportedis decided by an enumerated, CI-byte-checked whitelist rather than by accident; out-of-surface contracts name the offending construct. - Cross-module linking (#809 closed). Bare-name calls across modules emit qualified C# and link under MSBuild/csc, covering both the CLI multi-input driver and the MSBuild task.
- MSBuild verify gate.
CalorVerify=trueruns Z3 contract verification inside builds; refutation warnings surface as MSBuild warnings with declaration attribution. - Mechanical weakening check.
calor verify --weakening-checkdecides whether a declaration's contract was weakened between two versions (postcondition relaxed or precondition strengthened), with an intact-or-strengthened verdict for CI gating.
Fixed
- Precondition guards are never elided on satisfiability results (#755). Only genuine ∀-proofs elide checks.
- Contract-level vacuity is loud. Jointly-unsatisfiable precondition sets no longer mint silent Proven verdicts.
%semantics corrected (bvsrem, C# remainder), out-of-32-bit literals refused instead of silently wrapped, and the flagship proven-contracts sample repaired to prove 14/14 soundly.
[0.9.0] - 2026-07-29
The Loop release: the agent edit–feedback cycle is now a first-class, measured product surface — one machine-readable envelope across every CLI command and MCP tool, a transactional MCP write path with warm project sessions, and millisecond-scale edit feedback. Measured on paired A/B epochs: the new loop tooling cuts agent tokens-to-green ~35%, and Calor's enforcement caught 9/9 seeded defects where the C# toolkit caught 4/9.
Added
- Transactional MCP write path with project sessions.
calor_session_open/calor_session_closehold parsed project state;calor_file_writeruns heal → check → atomic-apply-or-reject with the full diagnostic envelope on reject, project-wide reference checking, and write confinement under a pinned root (calor mcp --root). - Fault-tolerant parse mode. Broken files produce partial ASTs plus diagnostics (never a compile pass), so sessions keep working context across syntax errors; parser depth guards prevent runaway nesting from killing the process.
- Warm feedback. Sessions reuse parse/bind state and a lazy call-target index; MCP edit→envelope latency measures P50 2 ms / P99 9 ms on a pinned 10k-line fixture, with
calor watchincremental rebuilds at P50 27 ms. Telemetry streams (mcp-write/2,watch-rebuild/1) journal per-edit latency breakdowns. - Verification-outcome honesty. All verification outcomes route through a single five-status choke point (
proven | refuted | unknown | timeout | unsupported); refuted contracts carry concrete counterexample models; a committed fixture corpus pins every status in CI.
Changed
- One envelope everywhere. Every diagnostic-producing CLI command and MCP tool emits the shared envelope schema v1.1 (diagnostic code, span, enclosing declaration ID, severity, fix hint, verification payload) — 100% coverage over the enumerated surface, enforced by CI conformance tests. See CLI envelope schema.
calor verifyexits 1 on refuted contracts (missing files and compile errors too); proven/inconclusive outcomes keep exit 0.
Fixed
- CLI exit codes propagate on error paths across
verify,convert,coverage,benchmark,migrate, and theeffectssubcommands (previously stomped to 0 by the invocation pipeline). - JSON mode always emits exactly one envelope document, including on error paths, with CLI-band diagnostics (
Calor1310–1312). - Counterexample rendering filters internal solver variables across all producers.
[0.8.0] - 2026-07-23
The correctness-hardening release: every exit-0-then-broken-dotnet build hole in the binding/rebind/shadowing family is now caught at calor -i with a clear diagnostic, plus a systemic pass to keep every diagnostic agent-friendly.
Breaking
- New hard-error diagnostics (
Calor0254–0258) reject programs that previously compiled. Programs that used to exit 0 and then fail a downstream C# build now fail earlier atcalor -i: array→concrete-collection (Calor0254), enclosing-scope shadowing (Calor0255), type-changing mutable rebind (Calor0256), foreach iteration-variable write (Calor0257), and same-scope duplicate§B(Calor0258). - Contract-verification result codes renumbered
Calor0700–0705→Calor0710–0715. Tooling filtering verification output onCalor0700–Calor0705must switch toCalor0710–Calor0715;Calor0700/Calor0701now unambiguously mean the semantics-version diagnostics.
Added
- Array-to-collection type error (
Calor0254).calor -irejects binding, returning, reassigning, or passing an array where a concrete generic collection (List<T>,HashSet<T>, …) is expected — e.g.§B{lines:List<str>} §C{File.ReadAllLines}— instead of emitting C# that fails with CS0029. Collection interfaces (IList<T>,IEnumerable<T>) are still accepted. - Local-shadowing error (
Calor0255). Rejects a§Bthat shadows a local, parameter, or loop variable already in an enclosing scope (CS0136), in both directions (an inner binding, or a loop variable reusing an enclosing name). Mutable rebinds (the accumulator idiom) and legal field-shadowing are unaffected. - Type-changing / mismatched mutable-rebind error (
Calor0256). Rejects a mutable§Breassignment whose value is a different, non-convertible type — from an explicit annotation, a literal, or (new) an inferred reference/call return type. Uses primitive-category comparison, so implicit numeric widening is never falsely flagged. - Foreach iteration-variable rebind error (
Calor0257). Rejects writing to a read-only§EACH/§EACHKViteration variable (CS1656);§Lfor-loop variables and§EACHindex counters stay reassignable. - Same-scope duplicate-binding error (
Calor0258). Rejects two§Breusing a name in one scope (CS0128); the C#→Calor converter now emits array/collection reassignments as reassignments rather than duplicate creation blocks. calor convert --passthrough. The CLI C#→Calor converter can now preserve unconvertible members verbatim as§CSHARPinterop blocks so the output always parses, reporting how many members were preserved.- Surface-spelled diagnostics. Every diagnostic that echoes a type now prints the compact surface spelling (
i32,str,bool,Option<str>) instead of the internal form, guarded by a test that scans the whole corpus for leaks. - Exemplar compile-checking.
calor self-check docsnow compiles every program in the agent syntax exemplar all the way through Roslyn's semantic model, catching type errors the Calor pipeline emits without complaint. - Converter §CSHARP fallback. When a C#-preserving mode is active and the emitted Calor for a member would not parse, that member is re-emitted as a
§CSHARPinterop block so the output is always valid Calor.
Fixed
- Scope-aware mutable-rebind codegen. The emitter now tracks declared variables in a scope stack, so a mutable
§Bin a closed sibling block re-declares (valid) rather than assigning to an out-of-scope variable (CS0103); loop variables,catch/usingbindings, and parameters are modeled too.
Changed
- CI hardening. The Calor-first guard exempts the
tests/tree (xUnit tests are C# by nature), and the Z3 download retries transient network failures instead of breaking the build.
[0.7.0] - 2026-07-16
The agent dev-loop release: Phase 1 of the agent-native strategy complete — six items, each hardened by adversarial review.
Added
- Source maps. The compiler emits
#linedirectives mapping generated C# back to.calrsource: downstream compiler errors, runtime stack traces, and debugger sessions report your.calrfile and line instead of a generated.g.cslocation. calor runandcalor test. One command to execute or test any.calrfile or directory — no MSBuild wiring. Effects enforcement on by default (--permissiveto relax, violations now visible as warnings),--verify/--contract-modepass-through, process timeouts, real exit codes.- Structured diagnostics.
--format text|json|sarifon compile andlint: stdout is always one machine-parseable document (status goes to stderr), early-exit errors included, honest exit codes. Schema documented in structured output. calor format --heal. Best-effort source-level repair for files too broken to parse — indentation re-derivation, closer stripping, chain-clause re-alignment — with every ambiguous decision reported perfile:line. New fixable indentation diagnostics (Calor0008/Calor0009/Calor0117) carry one-pass machine-applicable edits, and the MCPcalor_checktool auto-heals in agent loops.calor self-check docs. Machine-verifies the docs against the implementation — §-keywords vs the lexer, diagnostic codes, effect codes, and every fenced Calor example parsed with the real parser — and runs in CI, so documentation drift is now a build failure.calor watch. Debounced incremental recompiles with NDJSON structured output; incremental caching shares the MSBuild engine with hardened trust boundaries (content hashed from compiled bytes, effect summaries required for cache hits, outputs verified by hash). Plain-compile caching is opt-in via--cache.
Fixed
- Obligation fact scoping: guard facts were collected function-wide, so contradictory sibling branch guards could vacuously discharge every proof obligation in a function; facts are now scoped to the range they dominate with an UNSAT pre-check.
NullDereferenceCheckerorder-dependent classification ofunwrap_or/unwrap_or_default.Option/Resultcombinators resolve through effect manifests as pure-modulo-arguments; Calor surface types (?T,T!E) map to runtime manifest keys.- Agent-facing docs corrected (keyword accuracy, effect-code completeness) and now drift-guarded in CI.
Changed
- New diagnostic bands: 1300–1399 (CLI findings and command-level errors, incl. doc-drift codes).
Calor0008/Calor0009warnings fire on legacy tab/4-space-indented files (with attached one-pass fixes).
[0.6.8] - 2026-07-01
Added
calor fix --heal-closers— a source-level CLI that finishes theCalor0830auto-heal story. Closer-form syntax (§/F,§/M,§/L, …) hard-errors at parse time, socalor format/calor lint --fix— which parse the file first — can never read, let alone heal, it. The newcalor fix --heal-closers <root> [--log <file>] [--revert] [--dry-run]deletes legacy structural closers at the source level, rewriting a file into canonical indent-only form, and--revert --logrestores it byte-exactly. It is lexer-backed, so a§/Fembedded in a string literal or a//comment is left untouched, and removals are recorded as UTF-8 byte ranges so revert is exact even across non-ASCII text and CRLF endings. This delivers the CLI heal command deferred in v0.6.6.
Changed
- Single-sourced return-value classification in a shared
Analysis/ReturnShape. The "does this owner return a value" classification — forvoid/async-voidfunctions and methods, iterators, constructors, setters, and event accessors — was duplicated between theCalor0205pass and the contract verifier'sresultcheck. Both now defer to one classifier, which distinguishes the runtime shape (folding in async/iterator lowering) from the narrow header predicate (which keepsresultreferenceable in an iterator's postcondition, since an iterator still declaresIEnumerable<T>). The refactor is behavior-preserving and leaves codegen untouched, retiring the shared-ReturnShapefollow-up noted in v0.6.7.
[0.6.7] - 2026-07-01
Added
Calor0116— malformed four-field§F/§AFfunction headers are now a parse error. A header like§F{f1:Add:i32:pub}looks reasonable but is silently wrong: function headers take at most{id:name:visibility}, and the return type belongs in the signature ((...) -> type). Left unflagged, the parser read the extra field's type as the visibility and discarded the real visibility, emitting a void method (e.g.void Add() { return 0; }, then a CS0127 in the generated C#). The parser now reports it up front. Only§F/§AFare affected —§MT/§AMTlegitimately take a fourth modifier field.Calor0205— a value returned from a no-value owner is now a hard error. An always-on pass flags a value-returning§R exprin avoid/async-voidfunction or method, an iterator, a constructor, a property/indexerset/initaccessor, or an eventadd/removeaccessor — cases that previously produced non-compiling C# (CS0127 / CS1622), the classic one being a correctvoidheader followed by§R INT:0. Being always-on, it is deliberately conservative for zero false positives: it flags only expressions that are definitely a value and never a valid void statement-expression, leaving calls,new,await, and++/--untouched. Together withCalor0116, this closes the deferred "value returned from void function" gap from v0.6.6.
Documentation
- Every agent-readable surface was swept to indent-only syntax. The MCP primer, the editor/agent instruction templates,
README.nuget, the evaluation skills doc, and the correct-Calor fields of the JSON resources were corrected so no agent-facing material still shows removed closer-form tags, four-field headers, or other syntax the compiler rejects — with a new compile-time guard that fails if any surface drifts back to teaching non-compiling forms.
[0.6.6] - 2026-07-01
Fixed
- The
calor://primerMCP resource now compiles. The agent primer served atcalor://primertaught syntax the compiler rejects today — closer-form tags (§/F,§/M,§/I,§/L), ULID IDs,§RESULT, and empty§R— so an agent onboarded from it at session start wrote non-compiling Calor. It was rewritten to be fully indent-only and empirically compilable, with 3-field§Fheaders, arrow signatures, BCL-only effectful calls, a "Common mistakes" section, and a quick reference. Calor0830(legacy closer form) is now auto-healable. Its remediation previously told users to runcalor format, which parses the file first and aborts on the very error it was meant to fix — a dead end. The diagnostic now attaches a quick-fix that deletes the closer line, surfaced through the LSP quick-fix and thecalor_check applyMCP tool, and the message explains the block ends at its body's dedent.
Documentation
- Teaching and reference docs no longer show removed closer-form syntax. The Markdown docs still claimed closers were "still accepted" and showed closer-form / stale pseudo-syntax, so an agent following Calor's own docs wrote non-compiling Calor. The false claims were corrected and the stale if / loop / match / class / try-catch examples were modernized to current indent-only syntax — each verified to compile.
Tests
- Compile-time guards keep the primer honest in both directions.
PrimerCompilesTestsproves every correct module the primer teaches compiles under the same optionscalor_compileuses by default;PrimerMistakesRejectedTestsproves every example in the primer's "these do NOT compile" section genuinely fails to compile — so Calor's own onboarding materials can't drift into teaching non-compiling code. Drift guards keep the curated mistake set in sync with the primer.
[0.6.5] - 2026-06-30
Fixed
- The
TokenEconomicsbenchmark metric now reports the composite it computes (the discarded-composite bug, #668). The calculator computed a composite advantage — the geometric mean of the token, character, and line ratios — and then discarded it, reporting the raw token-count ratio only despite the metric being namedCompositeTokenEconomics. The category now reports the composite. The metric is deterministic, so its 95% CI equals its point estimate. This lifts the headline numbers — TokenEconomics from1.11×(token-only) to1.42×(composite) and overall from1.28×to1.32×— purely as a measurement correction, not a Calor improvement. The honest caveat stands: Calor still uses more raw tokens than C# on small programs (the§-sigil premium), but is more compact once character and line counts are included.
Changed
- The deferred v0.7
TokenEconomicsgate was recalibrated against the corrected metric. The old token-only target (lower-95%-CI > 1.122) is superseded by a composite gate of ≥ 1.40×, anchored to the measured 1.42× baseline. The public Token Economics metric page was corrected — it had previously and incorrectly reported the category as "C# wins".
[0.6.4] - 2026-06-16
Fixed
- Parser: an elided
§Ccall no longer steals the parent block's terminatingDedent. An elided§C{X}/§C{X} §A argcall that was the last statement of a function body followed by a sibling declaration (e.g. another§F) previously failed withCalor0100: Expected statement but found Func. Discovered while modernizing the TypeSystem sample for this release.
Added
- 7 new TokenEconomics benchmark fixtures broadening corpus coverage of v0.6.3 expression-context call elision and v0.6 bind-inference (parser, formatter, delegation, and aggregation shapes), plus two neutral controls. Honest note: the
TokenEconomicscategory scores raw token count only, and Calor's§-sigils cost more tokens than the equivalent C# on small programs, so these representative fixtures left the category at 1.11x — the v0.7TokenEconomicsgate remains open.
Internal
- The TypeSystem sample and the
04_option_resultE2E scenario were modernized to canonical v0.6.3 syntax — a legacy triply-nested§OK{§ARR…}array form (an artifact of mass C# → Calor conversion) was replaced with the canonical§OK value/§ERR "msg"short form, fixing the generated C# fromResult.Ok<object, string>(new object[]{…})toResult.Ok<int, string>(100).
Documentation
- v0.6 bind-inference RFC §7 — the
Calor0250open question is resolved. The diagnostic has always shipped as a hard error; the "promote warning→error in v0.7?" bullet was a stale carry-over and is now marked resolved, backed by a permanent corpus-clean test pinning zero bind-inference firings across the sample and benchmark corpus.
[0.6.3] - 2026-06-13
Added
calor fix --elide-call-closersbulk migrator. Newcalor fixsubcommand that rewrites existing.calrsource trees to the v0.6.x call-closer-elided form: zero-arg§C{X} §/C→§C{X}and same-line one-arg§C{X} §A arg §/C→§C{X} arg. Multi-line forms, named-arg (§A[name] x), multi-arg, andref/out/inarg modifiers are left untouched. Includes a canonical-emit safety net (re-parse the migrated source, re-emit both ASTs, drop the file's edits on any divergence) and--revert --log <file>for byte-for-byte round-trip. Mutually exclusive with--drop-structural-idsand--compact-ids; supports--dry-run.- LSP quick-fixes for strict bind-inference diagnostics
Calor0251/Calor0252/Calor0253. Each diagnostic now ships aSuggestedFixthat inserts the recommended:typeannotation right before the closing}of the bind's attribute block. Templates::Option<object>(for§NN),:object?(fornull),:Vec<object>/:Map<object, object>/ etc. arity-aware per the matched generic factory, and:f64(for ambiguous numeric). Calor.LanguageServer.DocumentState.Reanalyzenow runsBindValidationPassso strict-bind diagnostics (and their quick-fixes) surface in editors; previously the LSP only ran the lexer/parser/binder and these diagnostics were CLI-only.
Changed
- Expression-context
§Ccalls now elide§/Cby default for one-argument forms.CalorEmitter.Visit(CallExpressionNode)extends the v0.6.1 zero-arg elision and the v0.6.2 stmt-context one-arg elision to expression context:§C{target} arg(no§A, no§/C) when the argument is unnamed, the rendered first token is in theStartsWithExpressionStarterwhitelist, and we are not inside an inline-sibling context. - Strict bind-inference diagnostics
Calor0251/Calor0252/Calor0253are now default-on. These flag bindings that cannot infer a concrete type without an explicit:typeannotation: untyped§NN/null, well-known generic factory calls (Vec.empty,List.empty, etc.), and binary ops mixing integer and floating-point literals. Opt out for one release with--no-strict-bind-inference(CLI) orCompilationOptions.StrictBindInference = false(SDK).
Fixed
- Parser:
Calor0150no longer fires across sibling-statement boundaries. When the next expression-start token after a one-arg elided call is on a different line, it is a sibling statement, not an ambiguous second positional arg. - Emitter:
§LAMbody,§WITHtarget, and§LIST/§HSETelement emit sites now useAcceptInInlineSibling. These same-line sibling positions previously used rawnode.X.Accept(this), which could silently corrupt the AST after the one-arg expression-context elision landed.
[0.6.2] - 2026-06-10
Added
- Elision-aware TokenEconomics benchmark fixtures (
VoidSequence,LogPipeline,PairLogger) exercise the new statement-context§/Celision path. Corpus is now 210 programs.
Changed
- Statement-context
§Ccalls now elide§/Cby default (when safe).CalorEmitter.Visit(CallStatementNode)rewrites zero-argument calls as§C{target}and one-argument unnamed calls (with safe-prefix arguments) as§C{target} arg. Mirrors the v0.6.1 behavior for expression-context calls. Elision is gated byUseImplicitCallCloserand suppressed in inline-sibling contexts.
Removed
calor diagnoseCLI command removed. Deprecated in v0.5.x with a stated removal target of v0.6.0; v0.6.2 completes that deprecation. For machine-readable diagnostics use thecalor_checkMCP tool withaction: "diagnose"(orcalor_compilewith automatic fix application).
Fixed
- Contract verifier: class methods, user-defined types, and visibility preservation.
ContractSimplificationPassnow preservesVisibilityso the verifier reaches§MTmembers.ContractVerificationPasswalks class-method bodies. Z3 translator gained support for user-defined types and dot-path field access (a.b.c).
[0.6.1] - 2026-06-09
Changed
ConversionContext.UseImplicitCallClosernow defaults totrue(wasfalsein v0.6.0). The C# → Calor converter now elides§/Cfor zero-argument calls by default, producing more idiomatic Calor output. The opt-out (UseImplicitCallCloser = false) is preserved.
Compatibility
-
Calor source emitted by v0.6.1 may not parse on v0.6.0 or earlier
calortoolchains. The new default emits more zero-arg§Ccalls without explicit§/C. Sources that exercise the newly-fixed parser layouts (zero-arg§Cimmediately beforeDedent, or followed by a same-column sibling opener) will mis-parse on v0.6.0. To produce v0.6.0-compatible output from v0.6.1, use any of:- CLI single-file:
calor convert --explicit-call-closers <input.cs> - CLI project migration:
calor migrate --explicit-call-closers <path> - MCP
calor_convert/calor_migrate:"explicitCallClosers": true - SDK:
new ConversionOptions { UseImplicitCallCloser = false }
Round-trip (
C# → Calor → C#) remains semantic/structural; the intermediate.calris intentionally not byte-identical to v0.6.0 converter output unless the opt-out is used. - CLI single-file:
Fixed
- Parser:
§Cstandard form no longer swallows trailingDedent. Previously, a zero-arg§Cimmediately followed by the end of its enclosing block could corrupt the structural parse of the surrounding method or§IFbody. Now correctly distinguished from indent-aware block terminators. - Parser:
§Cno longer absorbs a same-column sibling structural opener on the next line. A sibling§IF/§MATCH/§NEWon the next line at the same indent is no longer silently absorbed as the call's inline argument. BothParseCallExpressionandParseCallStatementnow gate the inline-arg form on the candidate argument starting on the same source line as§C{target}. See Calls reference rule 6. - Emitter: zero-arg
§Cinside an inline-sibling context now keeps explicit§/C. With the new default, naively eliding§/Cfrom a zero-arg call emitted inside another call's§Achain or inside an array/§ARR/§ROW/§SALLOC/§IDX2Dinitializer caused silent AST corruption (e.g.M(A(), 2)round-tripping asM(A(2))). The emitter now tracks an inline-sibling-context counter; zero-arg§/Celision is suppressed whenever a call is emitted inside such a context. Top-level / leaf-position calls (binding initializers, return values) still elide as before. - Parser:
§Cstatement form now supports zero-arg implicit close before sibling statements. Previously a zero-arg§C{target}followed by a sibling statement on the next line at the same indent reportedCalor0100. The statement-form parser now recognizes the zero-arg implicit close when the current token is not§A,§/C,Dedent, orEof.
[0.6.0] - 2026-06-04
Added
§Ccall-closer elision (RFCv0.6-call-closer-elision). Expression-context§C{target}calls may now omit the trailing§/Cin two cases: (1) zero arguments —§B{n} §C{items.Count}is equivalent to§B{n} §C{items.Count} §/C; (2) exactly one inline argument (no§A) —§B{y} §C{Math.Abs} xis equivalent to§B{y} §C{Math.Abs} §A x §/C. The parser disambiguates nested elided calls (e.g.,§C{Foo.bar} §C{Baz.qux} y≡Foo.bar(Baz.qux(y))) by counting consecutive§/Cclosers relative to enclosing§Adepth. Trailing member access on inline arguments binds to the argument (§C{Identity} obj?.Length≡Identity(obj?.Length)); trailing member access on zero-arg calls binds to the call result (§C{Maybe}?.Length≡Maybe()?.Length). The explicit§A/§/Cform continues to parse unchanged. See Calls reference.Calor0150 AmbiguousCallContinuation— New diagnostic in the reservedCalor0150-0159range. Fires when an elided§Calready consumed one inline argument and is followed by either a second expression-start token or a§Atoken. The fix message recommends the explicit form.ConversionContext.UseImplicitCallCloseremitter flag. Opt-in property onMigration/ConversionContext. Whentrue,CalorEmitterelides§/Cfor zero-argument calls. Defaultfalsefor backward compatibility. One-argument elision is intentionally deferred to v0.6.1 pending context-aware tracking inside Lisp argument lists.§Bbind-inference formalization (RFCv0.6-bind-inference-formalization). The four supported§Bforms —§B{name}(requires initializer),§B{name} initializer(inferred),§B{name:type}(explicit, no initializer),§B{name:type} initializer(explicit wins) — and the binder's shallow inference rule are now documented at Bindings.Calor0250 BindRequiresTypeOrInitializer—§B{name}with no:typeand no initializer is now a hard error reported throughBindValidationPass. Replaces the pre-v0.6 silent fallback that boundxasINTand produced wrong-typed C# with no diagnostic.Calor0251/Calor0252/Calor0253strict-mode bind-inference diagnostics (opt-in via--strict-bind-inference). Three new diagnostics in theCalor0250-0259range, each silenced by an explicit:typeannotation, scheduled to become default-on in v0.7:Calor0251 BindCannotInferNullLiteral— fires on§B{x} §NNor§B{x} null.Calor0252 BindCannotInferGenericReturn— fires on§B{x} §C{Vec.empty} §/Cand other well-known generic factory targets.Calor0253 BindAmbiguousNumeric— fires on§B{x} (+ INT:0 FLOAT:0.0)— a binary op mixing integer and floating-point literal operands.
- Two new syntax-reference pages — Bindings and Calls, with full disambiguation tables, examples, and diagnostic catalogues.
- v6 compact stable identifiers (default).
IdGenerator.Generate(IdKind)now mints 12-char Crockford-lowercase compact IDs (f_7k9m2npqrstv). The legacy 26-char Crockford-uppercase ULID form (f_01J5X7K9M2NPQRSTABWXYZ12) remains accepted by the parser, validator, and migration tooling. Saves ~9.7 tokens per ID in agent-facing serialisations. calor fix --compact-ids <root>— bulk repo-wide migrator from legacy ULID payloads to v6 compact payloads. Two-pass design with deterministic compact derivation, within-file and cross-file collision detection, and byte-exact revert via--revert --log <file>. Idempotent on already-migrated source.IdValidatoraccepts both compact and legacy ULID forms. New predicatesIsCompactId,IsLegacyUlidId, andIsCanonicalId. NewCalor0821 LegacyUlidPayloaddiagnostic code reserved for the opt-in lint that flags ULID payloads.
Changed
Migration/CalorEmitter.Visit(CallExpressionNode)— Zero-argument calls in expression context now conditionally elide§/CwhenConversionContext.UseImplicitCallCloseristrue. Multi-argument and one-argument paths are unchanged in v0.6.0 (zero-arg-only elision) pending the v0.6.1 context-aware enablement.
Fixed
- Binder no longer silently defaults
§B{x}toINT. A§B{name}with neither a:typeannotation nor an initializer was silently treated asINTby the pre-v0.6 binder, producing wrong-typed C# with no diagnostic. v0.6 surfaces this asCalor0250.
[0.5.1] - 2026-06-03
Added
- Indent-only Calor source — Calor source is now indent-delimited end to end. The parser, migration emitter (
Migration/CalorEmitter), andcalor formatall produce/accept indent form as canonical. Closer-form structural tags (§/F{id},§/M{id},§/I{id},§/L{id}, …) have been removed from the emitter and rejected by the strict CLI compile path. The09_codegen_bugfixesself-test fixture was migrated alongside; round-trip emission stays byte-identical. calor --input … --output … --allow-legacy-closers— Escape hatch on the CLI compile path for users mid-migration. Default is strict (legacy closer form producesCalor0830);calor formatrewrites a file in canonical indent form.CompilationOptions.RejectLegacyClosers— Opt-in compilation flag; the CLI sets it totrueby default, other API surfaces (MSBuild<CompileCalor>, MCP tools, LSP) keep the lax default for now.calor fix --drop-structural-ids <root>— Bulk, mechanical, byte-reversible source rewriter that strips{id}from structural closing tags. Records every removal in amigration.log.jsonand supports--revert --log <file>to restore the original bytes exactly. Seedocs/cli/fix.md.Calor0820 LegacyStructuralId/Calor0830 LegacyCloserForm— Opt-in lints flagging legacy IDs on closing tags and legacy closer-form structural tags, withfixpatches pointing atcalor fixandcalor formatrespectively.- Optional closing-tag IDs everywhere — Structural closing tags (
§/M,§/F,§/AF,§/L,§/I,§/TR,§/CL,§/IN,§/PR,§/MT) may omit the trailing{id}block. Both forms continue to parse; the parser pairs closers with their nearest matching opener by structural nesting. - Phase 5 — Product docs migrated to indent-only syntax. README,
docs/, andwebsite/content/now teach indent-form Calor as the canonical surface; closer-form is mentioned only in legacy callouts that point atcalor fixfor migration.
Changed
- Lint no longer flags leading indentation or blank lines. With indent form now canonical, the two formatting lint rules introduced for the closer-form "agent-optimized" surface (leading whitespace, blank lines) have been removed from both
calor lintand thecheckMCP tool. Indentation and blank lines are first-class. - Benchmark metric calculators score indent form, not closer tags. The four heuristic calculators under
tests/Calor.Evaluation/Metrics/used to award credit for the presence of paired structural closing tags as a proxy for "scope boundaries are explicit". With indent form canonical, the dedent IS the scope-boundary signal, so those bonuses now reward indented body lines per structural opener. Net score magnitude is preserved.
Fixed
Migration/CalorEmitter.Visit(CatchClauseNode)— Catch filters now emit§WHEN(matching the token form the parser produces and the§WHENalready emitted by match-arm guards). Previously emitted a bare lowercaseWHENthat did not round-trip cleanly.MatchExpressionNodeas a§Bbinding initializer — match expressions used as binding initializers now emit indented§Karms relative to the enclosing block. Previously hardcoded 2/4-space indents could triggerCalor0099dedent errors when the binding lived inside a deeper function body.
[0.5.0] - 2026-04-22
Added
- Roslyn 5.3.0 upgrade — Migration pipeline now uses Roslyn 5.3.0 (C# 14 support), enabling conversion of modern C# files using lambda parameter modifiers,
outin lambda parameters, and other C# 13/14 features. LanguageVersion.Previewparse option — The C# parser now accepts the broadest possible C# syntax.
Changed
- Non-exhaustive match on
Option<T>/Result<T,E>is now an error — exhaustive match on known sum types is mandatory syntax (Calor0500). - Microsoft.CodeAnalysis.CSharp upgraded from 4.8.0 to 5.3.0 across all projects.
[0.4.9] - 2026-04-21
Added
- Cross-assembly IL analysis — Opt-in compile-time analysis that traces method calls through referenced .NET assemblies to discover effects not covered by manifests. Enabled via
<CalorEnableILAnalysis>true</CalorEnableILAnalysis>. Handles async state machines, iterator methods, delegate creation, and virtual dispatch. See Cross-Assembly IL Analysis guide. - Cross-module effect propagation — Multi-file Calor projects now verify effect contracts at file boundaries. A caller that invokes a public function declared in another module must declare that callee's effects. Violations produce
Calor0410; public functions without§Eproduce the newCalor0417warning. - Multi-file CLI —
calor --input a.calr --input b.calrcompiles multiple files and runs the cross-module effect pass across them. Single-file invocations are unchanged. - MSBuild cross-module enforcement — The
CompileCalortask runs the cross-module pass over every.calrin the project. Works correctly on warm builds via persistent per-module effect summaries in the build cache. - Effect summary cache (schema v2.0) — Each module's public function declarations, internal names, and call-site listings are cached alongside the content hash, so incremental builds retain complete cross-module coverage without re-parsing skipped files.
- Cross-Module Effect Propagation guide — Contract model, bare-name vs. qualified calls, incremental build semantics, CLI + MSBuild integration.
Changed
--inputoption in thecalorCLI now accepts multiple values.- Build state cache format bumped from
1.0to2.0— existing caches auto-invalidate on first build after upgrade. - Options hash includes
EffectKindenum shape — future enum changes automatically invalidate caches, preventing stale summaries from silently dropping effects.
[0.4.8] - 2026-04-20
Added
- Incremental compilation —
CompileCalorMSBuild task now owns all incremental logic with a two-level cache gate: (mtime, size) stat check then SHA256 content hash. Global invalidation on compiler DLL, options, effect manifest, or output directory changes. calor effects suggestCLI command — Analyzes Calor source files and generates a.calor-effects.suggested.jsonmanifest template for unresolved external calls. Supports--jsonfor agent consumption,--mergefor additive updates to existing manifests.- Shared
ExternalCallCollector— Extracted fromInteropEffectCoverageCalculator, extended to walk class methods and constructors. Resolves variable types via§NEWinitializer scanning. - Incremental build benchmark — Measures cold, warm (no changes), and warm (1 file changed) build times
- Effect manifests .NET ecosystem guide — ~170 covered types, resolution mechanics, custom manifest authoring, CLI tools
[0.4.7] - 2026-04-20
Added
- Static analysis for class members — The
--analyzeflag now examines methods, constructors, property accessors, operators, indexers, and event accessors (previously only top-level functions were analyzed) - Verification-gated reporting —
--analyzeonly reports proven findings by default (Z3-confirmed or constant analysis); use--all-findingsfor lower-confidence results - Taint hop-count tracking — Taint analysis tracks propagation steps; single-hop parameter-to-sink flows filtered by default to reduce false positives
- Bug pattern detection in class members — Division by zero, null dereference, integer overflow, off-by-one, path traversal, command injection, and SQL injection detection now covers all class member bodies
- Arity-aware overload resolution — Correct overload resolved by argument count, preventing wrong return types from flowing into Z3
- Constructor initializer binding —
: base()/: this()arguments visible to bug pattern checkers - 33 new unit tests for class member binding, scope, overloads, dataflow, and end-to-end analysis
- New
--all-findingsCLI flag for showing all analysis findings including inconclusive results - New static analysis documentation page
Fixed
- False positive elimination — Unhandled expression types return opaque expressions instead of literal zero, eliminating false division-by-zero reports
- this.field shadowing —
this.fieldresolves from class scope, not method scope - Throw-to-catch CFG edges — Throw statements inside try blocks now flow to catch blocks
- Assignment dataflow —
x = 1no longer reportsxas used before write
Validated
- 47 open-source projects scanned — 23 verified findings, ~90% true positive rate
- Real findings: ILSpy null dereferences, FluentFTP path traversal, ASP.NET Core path traversal
[0.4.6] - 2026-04-18
Added
- Effect system: .NET framework manifests — Tier B effect manifests for 30+ common .NET framework interfaces (ILogger, DbContext, HttpClient, ControllerBase, etc.)
- Effect system: ecosystem library manifests — Manifests for Serilog, Newtonsoft.Json, Dapper, MediatR, AutoMapper, FluentValidation, Polly
- Effect system: BCL manifest expansion — New manifests for System.Text.Json, Regex, Concurrent collections, Crypto types
- Effect system: variable type resolution — Enforcement pass resolves instance method calls via initializer tracking
- 95 new enforcement tests (210 total)
Fixed
- Effect system: unified resolver — Consolidated three parallel effect systems into a single manifest-based resolver
- Parser: compound effect codes — Fixed silent mis-parsing of chained compound codes
[0.4.5] - 2026-04-16
Fixed
- Restrict expression-only match case to lambda-only patterns
- PLIST nested call depth, call-as-pattern, OPTION compaction
Earlier Releases
See the full changelog on GitHub for versions prior to 0.4.5.