# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.0.3] - 2026-06-24

### Added
- `--templates <DIR>` CLI flag and `INGOT_TEMPLATES_DIR` environment variable to
  explicitly set the templates directory, enabling installed-package use without a
  local `templates/` copy.

### Fixed
- RPM, deb, and AppImage packages no longer fail with "Could not find templates/
  directory" when run outside the source tree. The template-search chain now
  includes `<exe>/../share/ingot/templates/` (FHS-relative, covers standard
  `/usr/bin` installs) and `/usr/share/ingot/templates/` (absolute fallback).
- Improved error message when an explicit `--templates` path does not exist.

### Added
- `--emit-tinyfsm` flag: emit C++/tinyfsm event artifacts for `event = true`
  keys -- `dm_key_events.hpp` (one empty `tinyfsm::Event` struct per event key)
  and `dm_key_events_wrapper.hpp/.cpp` (a `send_tinyfsm_event_by_key` switch
  fanning a runtime `key_id` to its typed event). Opt-in and additive:
  default-off, independent of `--no-events`, C99 output byte-for-byte unchanged
  when off. The dispatch target is a consumer-provided `send_tinyfsm_event` seam
  (via the consumer's `fsmlist.hpp`); ingot never defines a `FsmList`.
- tinyfsm test submodule (`deps/tinyfsm`) and C++ fixture (`tests/fixtures/cxx`)
  that compiles, links, and runs the generated wrapper against real tinyfsm,
  wired into `invoke test`.
- Rust integration tests (`tests/codegen_tinyfsm.rs`) asserting the generated
  event-struct, wrapper-switch, and flag-off behavior.
- Rust integration tests (`tests/codegen_determinism.rs`) asserting byte-identical
  output across two runs of every example model (the regression test for the
  deterministic-codegen fix below).

### Fixed
- Codegen is now deterministic. The perfect-hash seeds for boolean, integer, and
  string storage were drawn from system entropy (`rand::rng()`), so two runs on
  the same model produced different `*_HASH_SEED_*` defines and table layouts in
  `boolean_storage.c` / `integer_storage.c` / `string_storage.c`. Seeds are now
  derived deterministically from the key set (FNV-1a, with a deterministic retry
  until the CHM hash verifies), so identical input yields byte-identical output
  every run -- committed generated code no longer re-diffs on regeneration. The
  hash *algorithm* (CHM / 2-seed Jenkins) is unchanged; only seed *selection* is.

## [1.0.1] - 2026-05-07

### Added
- CycloneDX SBOM generation in release workflow
- THIRD_PARTY_LICENSES bundled in release artifacts
- Windows .exe and AppImage builds in CI

## [1.0.0] - 2026-04-06

### Added
- GitHub Actions CI workflow: fmt, clippy, coverage gate, build, test, Cobertura publish
- GitHub Actions release workflow: Linux tarball, Windows exe, .deb, .rpm, AppImage,
  crates.io publish, GitHub Release with all artifacts
- User guide (docs/user-guide.md): schema reference, API reference, build integration
- Manpage (docs/ingot.1): CLI options, exit codes, generated files
- Kaitai-inspired TOML data model schema with serde deserialization
- First-class enum definitions with per-variant overrides
- Derived key instances with expression strings
- Data model validation (7 checks: duplicates, overflow, missing max_size, enum refs,
  read-only persistent conflict)
- Full example model (examples/full.toml): 38 keys, 4 classes, 3 enums, all features
- Pre-generated C output in examples/generated/ for all 3 models
- Jenkins lookup3.c final() hash — 10 cross-language test vectors from Python ref
- CHM perfect hash generation algorithm (pure Rust, no external deps)
- Integer storage C codegen: per-type hash tables, G arrays, get/set functions
- Key definitions C codegen: #define per key with encoded 32-bit value
- Jenkins hash C codegen: matching lookup3.c implementation
- Boolean bitfield storage C codegen: packed uint32_t words, SetBit/ClearBit/TestBit
- String storage C codegen: separate RO (const literals) and RW (fixed-size char arrays)
- Main data model API codegen: dm_key.h, dm.h, dm.c with type-dispatch get/set
- Namespace definitions codegen: dm_namespace_definitions.h
- Helper getter/setter codegen: dm_helpers.h/.c with static inline integral + string helpers
- Unity integration test generation: test_dm.c + CMakeLists.txt per model
- Target abstraction: --target flag wired to codegen, per-platform mutex in dm.c
- Persistence storage codegen: packed struct binary save/load for persistent keys
  - Filesystem I/O with magic number validation (sizeof XOR num_keys)
  - SyncToStorage/SyncFromStorage bridge between persistence struct and live hash storage
  - PersistenceStorage_IsKeyPersistent() key query
  - DataModel_LoadPersistentKeys/SavePersistentKeys API with 4 new return codes
  - Validation: read-only keys cannot be marked persistent
  - Generated Unity tests: file-not-found + save/load roundtrip

- dm_full.yaml manifest generation: YAML dump of resolved data model for downstream tools
- Tera template infrastructure (14 templates: dm, dm_key, dm_namespace_definitions, dm_helpers, integer_storage, boolean_storage, string_storage, jenkins_hash, key_definitions)
- Example data models: minimal.toml (5 keys), battery.toml (18 keys, port of UDM)
- 32-bit key encoding/decoding with bitfield layout
- Target abstraction for STM32, ESP32 (Xtensa/RISC-V), 8-bit MCU, Linux64
- CLI with --model, --output, --target, --verbose options
- Pre-commit hooks (cargo fmt, clippy, test)
- Unity test framework submodule (deps/unity)
- CLAUDE.md with project conventions

### Removed
- Derived key / instance support (InstanceDef, empty-expression validation) — not used in practice

## [0.1.0] - 2026-04-06

### Added
- Project initialization
