keleusma 0.2.0

Total Functional Stream Processor with definitive WCET and WCMU verification, targeting no_std + alloc embedded scripting
Documentation
# Task Log

> **Navigation**: [Process](./README.md) | [Documentation Root](../README.md)

Current sprint source of truth.

---

## Current Phase

**V0.1: First public release.**

- `keleusma-arena 0.2.0` published to crates.io on 2026-05-10.
- `keleusma-macros 0.1.0` published to crates.io on 2026-05-10.
- `keleusma 0.1.0` ready to publish (dry-run clean against the just-published dependencies).

## Active Milestone

V0.1-M3 substantially complete. The runtime carries Hindley-Milner inference, generics with traits and bounds, compile-time monomorphization, closures (rejected by the safe verifier under the conservative-verification stance), f-string interpolation, target descriptors, hot code swap, the WCET pipelined-cycle and WCMU byte cost model, and the embedding ABI for native functions. Tooling, examples, onboarding documentation, and pre-publication polish passes are complete.

## Outstanding TODO

The single remaining publication-side action is operator-driven.

- **Publish `keleusma 0.1.0` to crates.io.** The two dependencies (`keleusma-arena 0.2.0` and `keleusma-macros 0.1.0`) are live on the registry. `cargo publish -p keleusma --dry-run` succeeds against the registry-resolved dependencies; the package is 91 files, 1.3 MiB unpacked, 330.5 KiB compressed. The agent does not perform `cargo publish`; the operator runs `cargo publish -p keleusma` to complete the V0.1.0 release.

No development-side TODOs remain in this log. Future-work items belong in [BACKLOG.md](../decisions/BACKLOG.md) or [PRIORITY.md](../decisions/PRIORITY.md), where they are tracked alongside their architectural rationale.

## Task Breakdown

### Recent: pre-publication and publication push (2026-05-10)

| ID | Description | Status | Verification |
|----|-------------|--------|--------------|
| V0.1-M3-T54 | BYTECODE_VERSION reset to 1, shebang execution, version triage | Complete | Three asks. (1) `BYTECODE_VERSION` reset from 8 to 1 for the initial public release; pre-publication versions accumulated as the wire format iterated and would never proliferate. The reset is a one-line constant change plus golden-bytes test update (only byte 4 and the CRC trailer change). Triage confirmed `BYTECODE_VERSION` is the only candidate; no other manual version fields exist. (2) Shebang execution. Source scripts: lexer skips line 1 if it begins with `#!`, advancing to line 2 so error messages remain meaningful; `Lexer::new` does the strip. CLI accepts any readable file path (the `.kel` extension shorthand is generalised to "any path that names an existing file"). Compiled bytecode: new `strip_shebang_prefix` helper in `src/bytecode.rs` runs at the entry of `Module::from_bytes` and `Module::access_bytes`, returning the slice past the first `\n` if `bytes.starts_with("#!")`. The CRC trailer covers only the post-strip range so the shebang envelope is not part of the signed payload. CLI auto-detects bytecode versus source through `looks_like_bytecode` which checks for `KELE` magic at offset 0 or after a `#!...\n` envelope; bytecode is loaded through `Vm::load_bytes`, source through the compile pipeline. End-to-end verified: `chmod +x script.kel`, kernel runs through `#!/usr/bin/env keleusma`, returns 42; same for a shebang-prefixed compiled `.bin`. (3) Multiheaded functions with guards confirmed already supported (parser parses `when` clause, AST has `guard: Option<Box<Expr>>`, compiler dispatches accordingly, test exists at `src/parser.rs:1908`). 520 tests pass workspace-wide; clippy, format, rustdoc clean. |
| V0.1-M3-T53 | Bytecode header gains declared WCET and WCMU fields | Complete | The framing header gains two `u32` little-endian fields at offsets 16 and 20 carrying the declared WCET in pipelined cycles and declared WCMU in bytes per Stream-to-Reset slice. Convention: `0` means auto (runtime computes via the verifier as it always has); `u32::MAX` means overflow (the producer attempted to compute a bound but the result exceeded the field's range; safe `Vm::new` rejects with new `LoadError::WcetOverflow` or `LoadError::WcmuOverflow`); other values are the producer's declared bound mirrored from the rkyv body. `BYTECODE_VERSION` 7 → 8. `HEADER_LEN` 16 → 24, divisible by 8 to preserve rkyv body alignment. The compiler runs `verify::wcet_stream_iteration` and `verify::wcmu_stream_iteration` over Stream chunks at end of `compile_with_target` and populates `Module::wcet_cycles` and `Module::wcmu_bytes` with the maximum across them; atomic-total programs (no Stream chunks) ship with `0`. Golden bytes test updated to pin the new 160-byte serialization of `fn main() -> Word { 1 }`. `examples/zero_copy_demo.kel.bin` regenerated (252 → 268 bytes); `examples/zero_copy_include_bytes.rs` BYTECODE_LEN constant bumped accordingly. 520 tests pass workspace-wide; clippy, format, rustdoc clean. `cargo publish -p keleusma --dry-run` clean against the registry-resolved deps. |
| V0.1-M3-T52 | Documentation polish for keleusma-macros | Complete | README gained "Supported Input Shapes" enumerating accepted (named-field structs, unit/tuple/struct-style-variant enums) and rejected inputs (tuple structs, unit structs, unions). Module-level and derive-fn doc comments expanded with the same enumeration plus a docs.rs link to the parent trait. Crate stays intentionally minimal. Dry-run packages 8 files at 20.3 KiB compressed. 520 tests pass; clippy, format, rustdoc clean. |
| V0.1-M3-T51 | Publication-readiness verification for keleusma-arena and keleusma-macros | Complete | Both crates verified ready. Arena 0.2.0 dry-run packages 13 files at 77.1 KiB; tests pass under stable, MSRV pin (Rust 1.85) with both default and no-default-features, and against `thumbv7em-none-eabihf`. Macros gained per-crate LICENSE (copy of workspace LICENSE) and CHANGELOG.md (Keep a Changelog format with implementation-detail framing). Both dry-runs clean. 520 tests pass. |
| V0.1-M3-T50 | Move KString out of keleusma-arena | Complete | The `KString` type alias and its `&str`-specific allocation logic moved from `keleusma-arena` to a new `keleusma::kstring` module. Arena retains the generic `ArenaHandle<T>` mechanism and gains a public `unsafe fn from_raw_parts(ptr, epoch) -> Self` constructor for downstream typed wrappers. KString is now a newtype over `ArenaHandle<str>` (the orphan rule forbids inherent impls on foreign type aliases). Three KString-specific arena tests replaced with three `arena_handle_*` tests using `from_raw_parts` against a u64. Arena's `epoch_handle` example rewritten to demonstrate `ArenaHandle<u64>`. Arena CHANGELOG and README updated; keleusma main CHANGELOG gained KString entry. 520 tests pass. |
| V0.1-M3-T49 | keleusma-arena 0.2.0 publication readiness | Complete | Version bumped from 0.1.0 (already on crates.io) to 0.2.0. SemVer-correct minor bump under 0.x, signaling the substantive new public surface (epoch counter, `ArenaHandle<T>`, `EpochSaturated`, `Stale`, safe `Arena::reset` returning `Result`, `force_reset_epoch`, `reset_unchecked`, `reset_top_unchecked`, `epoch`, `epoch_remaining`). The 0.1.0 surface preserved unchanged; addition is purely additive. CHANGELOG and README updated. New `epoch_handle` example. Sibling crate dep version requirements bumped to `"0.2"` across keleusma, keleusma-cli, and keleusma-bench. |
| V0.1-M3-T48 | Pre-publication polish pass | Complete | Five items closed. (1) Four rustdoc warnings fixed (private-item links rewritten as prose; `Vm::reset_arena` corrected to `Vm::reset_after_error`). (2) `Module` re-exported from crate root so embedders write `keleusma::Module`. (3) New `CHANGELOG.md` at workspace root in Keep a Changelog format documenting V0.1.0 across language, runtime, verification, host interface, tooling, examples, documentation. (4) CI workflow split MSRV per-crate (arena 1.85, keleusma 1.87) and gained a `no-std` job building keleusma against `thumbv7em-none-eabihf`. (5) `keleusma-macros` Cargo.toml metadata enriched and a new README marks it as an implementation-detail crate. 519 tests pass; format, clippy, rustdoc clean. |

### V0.1-M3-T1 through T47 (rolled up)

| Range | Theme | Status |
|-------|-------|--------|
| T1–T9 | Type checker standalone, integration into compile pipeline, gap closing | Complete. New `src/typecheck.rs` with two-pass design. Multiheaded parameter types, native call distinguishing, pattern type checking against scrutinee, match exhaustiveness for enum/bool/unit/other, P3 error-recovery model via `Vm::reset_after_error`. |
| T10–T12 | Host-owned arena migration, KString boundary, native ABI context | Complete. Vm migrated to a borrowed shared reference to a host-pre-allocated `Arena` under a new `'arena` lifetime. Operand stack migrated to arena-allocated `Vec<T, BottomHandle>`. `Value::KStr(KString)` arena-allocated dynamic string boundary. New `NativeCtx<'a>` carrying arena context for natives that allocate arena-backed strings. Float width log2 added to wire format header (BYTECODE_VERSION 5). |
| T13–T25 | Hindley-Milner inference, generics, traits, monomorphization, closures | Complete. Robinson unification with occurs check. `Type::Var` inference variables. Generic functions, structs, enums with type parameters and trait bounds. Compile-time monomorphization with inference reach across literals, identifiers, function and method calls, casts, enum variants, struct constructions, tuple and array literals, if and match arms, field access, tuple-index, and array-index. Closures with environment capture and transitive nested capture; rejected by the safe verifier per the conservative-verification stance because indirect dispatch through `Op::CallIndirect` cannot be statically bounded. |
| T26–T38 | Target portability, decode optimization, B-list closures, conservative-verification stance, release-readiness | Complete. Target descriptor for cross-architecture portability with `host`, `wasm32`, `embedded_32`, `embedded_16`, `embedded_8` presets. Per-op decode caching for archived bytecode. B7 error propagation through resume value pattern with optional `Vm::resume_err` documentation alias. B8 (shared arena across multiple Vm instances) closed as not-applicable. Conservative-verification stance documented in [LANGUAGE_DESIGN.md](../architecture/LANGUAGE_DESIGN.md#conservative-verification); compile-time and verify-time rejection enforced for `Op::CallIndirect` and `Op::MakeRecursiveClosure`. CLAUDE.md, top-level README, and Cargo.toml metadata refreshed. |
| T39–T41 | WCET cycle and WCMU byte cost model | Complete. New `bytecode::CostModel` struct with `value_slot_bytes` and `op_cycles` fields. Bundled `NOMINAL_COST_MODEL` constant. WCET unit terminology shifted to "pipelined cycles" with explicit definition; calibration-factor / dilation-factor industry terminology adopted. New `keleusma-bench` workspace member calibrates pipelined cycles per opcode through a `CycleCounter` trait with built-in implementations for x86_64 (RDTSC), AArch64 (CNTVCT_EL0), and a portable `Instant`-based fallback; emits a generated `CostModel` source fragment. |
| T42 | Standalone CLI | Complete. New `keleusma-cli` workspace member providing the `keleusma` binary with `run`, `compile`, and `repl` subcommands modeled after Rhai's CLI ergonomics. Shorthand `keleusma file.kel` runs a script. Installs through `cargo install --path keleusma-cli --bin keleusma`. |
| T43 | Onboarding documentation | Complete. New `docs/guide/` section with `GETTING_STARTED.md`, `EMBEDDING.md`, `WHY_REJECTED.md`. Eight standalone scripts under `examples/scripts/` covering arithmetic, structs, enums, for-in, pipelines, multiheaded dispatch, f-strings, and method dispatch. Each runs through `keleusma run`. |
| T44–T47 | SDL3 audio piano-roll example | Complete. Three-channel piano-roll: square-wave melody, triangle-wave bass, square-wave harmony, four-bar I-vi-IV-V progression in C major auto-looping at 120 BPM with 16th-note tick resolution. SDL3 audio thread synthesizes samples; Keleusma main thread sequences notes per tick; thread-safe handoff via `Arc<Mutex<[Voice; 3]>>`. Hot code swap between two precompiled songs at the reset boundary; `s` + Enter to swap, Enter alone to quit. Example refactored from a workspace-member to a feature-gated `[[example]]` (`required-features = ["sdl3-example"]`) so workspace builds remain SDL3-free. Documentation pass surfaced the example from the top-level README, the docs knowledge-graph index, the embedding guide (where two latent doc bugs in the hot-swap snippet were also fixed), and the getting-started guide. |

### Earlier milestones (rolled up)

| Milestone | Theme | Resolved Decisions |
|-----------|-------|--------------------|
| V0.0-M0 | Crate extracted from Vows of Love and War workspace; knowledge graph created | R1–R21 |
| V0.0-M1 | Block-structured ISA transition, productivity verification, WCET analysis | R22, R23 |
| V0.0-M2 | For-in over arrays, tuple literals, utility natives, README, formal related work pass | (RELATED_WORK Sections 1–7) |
| V0.0-M3 | Data segment specification and implementation, singular-block enforcement, fixed-size field validation, slot-bounds verification, host slot-based interop, hot swap API on `Vm` | R24–R29 |
| V0.0-M4 | Cargo workspace conversion with `keleusma-macros`; `KeleusmaType` trait and derive; `IntoNativeFn` family; `register_fn` and `register_fn_fallible`; audio and utility natives migrated | R30 |
| V0.0-M5 | Two-string-type runtime discipline (`Value::StaticStr`, `Value::DynStr`); cross-yield prohibition on dynamic strings; documentation of the fifth (memory) guarantee | R31, R32, R33 |
| V0.0-M6 | Dual-end bump-allocated arena via `keleusma-arena` (extracted as a standalone crate, published as `keleusma-arena 0.1.0` on 2026-05-08); WCMU instrumentation per-op; native attestation API; auto-arena sizing through `Vm::new_auto`; bounded-iteration loop analysis; call-graph WCMU integration | R34–R38 |
| V0.1-M1 | Precompiled bytecode wire format with magic, total-length, version, target word and address widths (encoded as base-2 exponents), CRC-32 algebraic self-inclusion trailer; trust-skip API via `unsafe Vm::new_unchecked`; golden-bytes test pinning the exact serialization | R39 |
| V0.1-M2 | Phase 1: body format switched from postcard to rkyv 0.8 (BYTECODE_VERSION 4). Phase 2: zero-copy execution against a borrowed `ArchivedModule` via `Vm::view_bytes_zero_copy` with the `'a` lifetime parameter; per-access converters from archived to owned types for the execution loop | R40 (P10 fully resolved) |

## History

| Date | Summary |
|------|---------|
| 2026-05-21 | V0.2.0 pre-publish polish: Tier 1 through Tier 4 documentation audit. **Tier 1** (per-crate READMEs and examples overview): `keleusma-cli/README.md` had three call sites using the retired V0.1.x `i64`/`f64`/`String` surface — updated to `Word`/`Float`/`Text` in the shebang script example, the REPL session transcript, and the REPL return-type inference list (the corrected list `Word, Float, bool, Text, ()` matches `REPL_RETURN_TYPES` at `keleusma-cli/src/main.rs:30`). `keleusma-arena/README.md`, `keleusma-macros/README.md`, `keleusma-bench/README.md`, and `examples/README.md` were audited and judged accurate. **Tier 2** (RTOS demonstrator and standalone scripts): `examples/rtos/README.md` carried two stale figures, the `memory.x` description (640 KB FLASH / 384 KB RAM at the wrong offset) and the trust-load image size (~192 KB); both updated against the actual `memory.x` (768 KB FLASH / 256 KB RAM at `0x341C0000`) and the current ~140 KB trust-load image. `examples/scripts/07_fstring.kel` no longer ran under V0.2.0 (the lexer rejects f-strings at lex time with a clear diagnostic); replaced with `examples/scripts/07_refinement.kel`, a worked example of `newtype Counter = Word where nonneg;` with literal-elision compile-time admission and runtime construction check. Verified by `keleusma run`: outputs `100`. `examples/scripts/README.md` updated for the new slot 07 and the `Word`/`Float` rename in the 01_arithmetic row. `examples/rtos/MANUAL.md` and `examples/rtos/SPEC.md` audited and judged accurate. **Tier 3** (architecture, spec, reference): `docs/architecture/LANGUAGE_DESIGN.md` Hindley-Milner bullet under "Scope Inclusions and Exclusions" claimed Type::Unknown "remains as a transitional sentinel"; the CHANGELOG records B15 closed (Type::Unknown removed in V0.2.0); verified by `grep 'Type::Unknown' src/typecheck.rs` returning no hits. Updated the bullet and reframed the section heading from "Features now implemented under V0.1." to "Features implemented." `docs/spec/GRAMMAR.md` carried the same V0.1 framing in "Scope Inclusions and Exclusions" and two stale "Opaque type support is partial in V0.1.x" sections; rewrote all three to reflect the V0.2.0 `HostOpaque` first-class support (the `HostOpaque` marker trait, `Value::Opaque(Arc<dyn HostOpaque>)`, `host_arc` constructor, `downcast_ref` consumer path). `EXECUTION_MODEL.md`, `COMPILATION_PIPELINE.md`, `SUB_COROUTINES.md` (preliminary by design), `TYPE_SYSTEM.md`, `INSTRUCTION_SET.md`, `WIRE_FORMAT.md`, `STRUCTURAL_ISA.md`, `STANDARD_LIBRARY.md`, `GLOSSARY.md`, and `RELATED_WORK.md` were audited and judged accurate. **Tier 4** (decisions, process, roadmap, extras): `docs/decisions/PRIORITY.md` had one present-tense statement claiming `Value::DynStr` "remains for natives that do not need arena allocation". V0.2.0 removed Value::DynStr entirely; all dynamic strings are arena-resident `Value::KStr`. Added an inline V0.2.0 update note. `docs/decisions/BACKLOG.md`, `RESOLVED.md`, `docs/process/*.md`, `docs/roadmap/*.md`, and `docs/extras/*.md` were audited and judged accurate. PRIORITY.md and RESOLVED.md are intentionally historical records of decisions resolved at a point in time, not evergreen statements; BACKLOG.md already carries explicit "V0.2.0 status." headers on items whose situation changed. |
| 2026-05-21 | V0.2.0 pre-publish polish: top-level `README.md` and all of `docs/guide/` audited and corrected. **README.md**: (B1) The pattern-matching example used a non-existent `format` native that would fail at the `use format` declaration. Rewrote the `describe` function to match an `enum Message { Body(Text), Code(Word) }` exhaustively without text-composition natives. Verified by running the rewritten code: emits `StaticStr("hi")`. (B2) Added the `signatures` cargo-feature row to the feature table; the Ed25519 module signing surface introduced in V0.2.0 was a headline omission. (B3) Added the `sdl3-example` row to the same table. (B4) Reframed the BACKLOG B10 reference to acknowledge that the portability foundation is in place; added a forward pointer to the `narrow-*` cargo features. (B5) Added a pointer to the `examples/README.md` overview in the Examples section. The Quick Start code was already correct (Word/Float/`Value::Int(21)`/pipe operator) and was re-verified end to end: `result: Int(42)`. **docs/guide/README.md**: Removed `,text` from the piano-roll and rogue command lines; updated FAQ row to V0.2.0. **GETTING_STARTED.md**: bumped the embedding `Cargo.toml` snippet to `keleusma = "0.2"` / `keleusma-arena = "0.3"` and stripped `text` from the piano-roll Next Steps command. **EMBEDDING.md**: corrected "four bundled libraries" to "three" because `stddsl::Text` was retired; fixed the `set_native_bounds` invocations which used invalid Rust named-parameter syntax (replaced with positional `(name, wcet, wcmu_bytes)`). **FAQ.md**: rewrote the "Opaque types compile but cannot cross the native boundary" section to reflect the V0.2.0 `HostOpaque` first-class support introduced in the V0.2.0 cycle; removed the stale "Bytecode 0.1.0 was yanked" entry. **BIG_NUMBERS.md**: replaced the "Division and modulo currently route to a stamped-zero-flag path" caveat with the V0.2.0 reality (dedicated `Op::CheckedDiv` and `Op::CheckedMod` with the `(h, l, flag)` shape; `i64::MIN / -1` and `i64::MIN % -1` corners handled through the overflow arm). **PIANO_ROLL.md**: dropped the `text` feature from the build instruction; reframed the section to note that static string literals are unconditional in V0.2.0. **ROGUE.md**: same `text`-feature removal. **WHY_REJECTED.md** and **COOKBOOK.md**: audited and judged accurate; no changes. **docs/README.md**: updated the FAQ Quick Reference row to V0.2.0. Verification: `cargo fmt --all -- --check` clean; the README quick-start code compiled and ran end to end. |
| 2026-05-21 | V0.2.0 pre-publish polish: items Q1 and D1 addressed. (Q1) Per-crate `CHANGELOG.md` files created for `keleusma-bench` and `keleusma-cli`. Both follow the Keep a Changelog 1.1.0 format used by the existing `keleusma-arena` and `keleusma-macros` changelogs. The bench changelog covers the V0.2.0 first-release surface (CycleCounter trait with Rdtsc/CntvctEl0/DwtCycCnt/InstantCounter, cpu_cycles_per_count scaling factor, BenchConfig with embedded_default, --cpu-hz override, MEASURED_COST_MODEL output, std/floats cargo features). The cli changelog covers the V0.2.0 first-release surface (run/compile/repl/keygen subcommands, --signing-key and --verifying-key flags, KELE auto-detect, shebang execution, keleusma-arena 0.3 substrate, ed25519-dalek 2 keypair generation, cargo install incantation). `cargo package --list` confirms both CHANGELOG.md files ship in the published tarballs. (D1) `actions/checkout@v4` bumped to `actions/checkout@v5` across all 15 use sites in `.github/workflows/ci.yml`. The v5 release uses Node.js 24 and resolves the deprecation notice GitHub emits about the forced June 2026 Node.js 20 → 24 migration. The `dtolnay/rust-toolchain` actions are toolchain installers rather than long-running Node-glue jobs and did not draw the deprecation notice; left unchanged. |
| 2026-05-21 | V0.2.0 pre-publish polish: items P1-P5 addressed and CI repaired. (P1) Crates.io, Docs.rs, License (0BSD), and CI badges added to top-level `README.md`. (P2) Crates.io, Docs.rs, License badges added to `keleusma-arena/README.md`, `keleusma-macros/README.md`, `keleusma-bench/README.md`, `keleusma-cli/README.md`. The arena badge uses an absolute OSI URL for the license link because the arena lib includes its README through `#![doc = include_str!("../README.md")]` and a relative `LICENSE` link triggers `rustdoc::broken_intra_doc_links` under the CI `-D warnings` flag. (P3) CHANGELOG.md V0.2.0 section reviewed and judged complete at the headline level. The 148-line section covers signing R42, ISA reset, wire-format reset (BYTECODE_VERSION 1), refinement-newtype saturation contracts, big-number arithmetic worked example, pattern-matched checked-arithmetic arms with guards, IFC label propagation with negative labels, ephemeral data partitioning (shared/private/const), the RTOS microkernel example, B13/B15/B18 closures, the `compile`/`verify`/`floats`/`text`/`shell`/`signatures` cargo features, the `keleusma-bench` crate and calibrated WCET cost models, the docs/spec reorganization. (P4) `cargo doc` verified clean across all five crates under the CI flags `RUSTDOCFLAGS="-D warnings -A rustdoc::redundant-explicit-links"`. (P5) `cargo test --workspace` passes end to end including doctests. **CI repair**. The Test (all features), Doc, and Examples (SDL3 feature) jobs were failing because `--all-features` cascades the mutually-exclusive `narrow-word-*` and `narrow-address-*` selectors into the narrowest configuration AND pulls in `sdl3-example`, which cmake-builds SDL3 from source. The SDL3 build needs X11, Wayland, and audio development headers that the Ubuntu runner does not have by default; the previous install installed `libsdl2-dev` (SDL2, wrong library). The Test (all features) job was renamed to Test (broad features) and now runs `cargo test -p keleusma --features signatures,shell` (the docs.rs feature set). The Doc job was rewritten to invoke `cargo doc` per-crate with the same feature set docs.rs renders, so the CI signal matches the published documentation. The Examples (SDL3 feature) job now installs the full SDL3 build dependency list (cmake, ninja-build, X11 dev libs, Wayland dev libs, audio dev libs, libdrm, libgbm, mesa GL libs, libdbus, libudev, libpipewire, libdecor) per the SDL3 Linux README. Local verification matrix: `cargo test --workspace` clean, `cargo test -p keleusma --features signatures,shell` clean, `cargo fmt --all -- --check` clean, `cargo clippy --workspace --all-targets -- -D warnings` clean, `cargo doc` per-crate under CI rustdocflags clean. |
| 2026-05-21 | V0.2.0 pre-publish polish: items A-G addressed. (A) `CLAUDE.md` status field refreshed: V0.1-M3 → V0.2.0 description, BYTECODE_VERSION 7 → 1 (V0.2.0 reset), 508 tests → ~826 lib + 53 rogue + 37 arena + 17 marshall + 17 zero-copy + 6 bench across the workspace. The signature/IFC labels/calibrated-WCET/docs reorganization headline added. The retired-features note (closures, f-strings, text bundle) added. (B) `README.md` Quick Start example surface fixed: `fn double(x: i64) -> i64` → `fn double(x: Word) -> Word`; same edits across the "Three function categories", "Pattern matching and guard clauses", "Generics and traits", "Coroutine yield and resume", and "Native Function Registration" sections. The remaining `i64`/`f64` mentions are in the Rust `register_fn` closure types and the `floats` feature blurb, where they correctly refer to Rust types. (C) `LICENSE` files copied from the workspace root into `keleusma-bench/LICENSE` and `keleusma-cli/LICENSE`; `keleusma-arena` and `keleusma-macros` already carried them. All four publishable child crates now ship a `LICENSE` in the package tarball. (D) `[package.metadata.docs.rs]` blocks added to `Cargo.toml` (features = compile + verify + floats + signatures + shell, deliberately not all-features because the narrow-* features are mutually-exclusive parametric selectors that conflict at the docs.rs build), `keleusma-bench/Cargo.toml` (features = std + floats), and `keleusma-cli/Cargo.toml` (rustdoc-args only). `keleusma-arena` already had `all-features = true`; `keleusma-macros` has no features so no block needed. (E) Workspace `Cargo.lock` tracking enabled: `Cargo.lock` removed from `.gitignore`. The detached `examples/rtos/Cargo.lock` remains gitignored because that crate carries heavy bare-metal git deps pinned at the manifest level. The committed lockfile makes the binary crates (`keleusma-cli`, the rtos demonstrator) reproducible from this commit; library consumers continue to resolve their own lockfile against their own constraints. (F) New `examples/README.md` overview enumerating each Rust embedding example with a one-line description, plus the three larger example crates (rogue, rtos, scripts) and cross-references to companion documentation. (G) Explicit `publish = ["crates-io"]` set on all five publishable crates (keleusma, keleusma-arena, keleusma-macros, keleusma-bench, keleusma-cli). Documents intent and prevents accidental publish to a private registry. Workspace builds clean; fmt clean. |
| 2026-05-21 | V0.2.0 pre-publish gap closure (items 1, 2, 3, and arena-version verification). Item 1: `--all-features` test failures resolved. Root cause for all five lib-side failures was missing `cfg` guards against the `narrow-word-*` and `narrow-address-*` feature flags. `target::tests::embedded_8_admits_int_only_program` and `embedded_8_rejects_string_literal` gated on `not(feature = "narrow-address-8")` (the embedded_8 target's 16-bit addr_bits_log2 exceeds the runtime ceiling under narrow-address-8). Three checked-overflow tests (`checked_mul_overflow_exposes_high_half`, `checked_overflow_arm_pattern_matches_literal_high`, `checked_overflow_arm_guard_falls_through`) gated on `not(any(narrow-word-8/16/32))` because they embed i64-sized literals (4294967296, 9223372036854775807) that overflow narrower Word types at lex time. Two integration tests (`tests/big_number_arithmetic.rs`, `tests/narrow_vm.rs`) and one rogue script test (`dungen_runs_floor_100_places_exit`) surfaced through follow-on iterations; same root cause, same gating treatment. Final `cargo test --workspace --release --all-features` is clean across all 16 suites. Item 2: CI workflow extended with four new jobs. `test-all-features` runs `cargo test --workspace --all-features` to catch the kind of feature-interaction failures item 1 addressed. `test-bench` exercises keleusma-bench with default features (six unit tests) and with `--no-default-features` (the no_std + alloc path). `examples-sdl3` builds the SDL3-feature-gated examples (piano_roll, rogue) on Ubuntu with libsdl2-dev installed. `doc` runs `cargo doc --workspace --no-deps --all-features` under `RUSTDOCFLAGS=-D warnings -A rustdoc::redundant-explicit-links` so future rustdoc regressions break CI. `rtos-n6-build` cross-compiles `three-task-n6` (twice, once with `keleusma-verify` for the WCET boot report) and `bench_n6` against `thumbv8m.main-none-eabihf`. Item 3: cargo issue #6313 collision resolved with `doc = false` on the `[[bin]]` declaration in `keleusma-cli/Cargo.toml`. The bin remains named `keleusma` so the user-facing install command `cargo install keleusma-cli --bin keleusma` is preserved; rustdoc skips the bin (its CLI documentation lives in the README), and the collision against the parent `keleusma` lib target is gone. `cargo doc --workspace --no-deps --all-features` is now warning-free. Arena 0.3.0 verification: pulled `keleusma-arena-0.3.0.crate` from crates.io and unpacked it. The published source files (lib.rs, Cargo.toml, CHANGELOG.md, README.md, src/, examples/) are bit-identical to the local source. Conclusion: the post-0.2.0 work (KString move, persistent .data region, resize, zeroing methods) was published into 0.3.0; no arena version bump required for V0.2.0. One follow-on clippy lint surfaced from the `--all-features` build of the rogue example: `type_complexity` on a five-tuple return type in `examples/rogue/ai.rs:479`. Introduced a `DescendOutputs` type alias to satisfy the lint. Final gates clean: `cargo test --workspace --release --all-features`, `cargo clippy --workspace --all-targets --tests --release --all-features -- -D warnings`, `cargo fmt --all -- --check`, `cargo doc --workspace --no-deps --all-features`. |
| 2026-05-21 | Pre-publish pass for V0.2.0: items 1 through 13 of the publication checklist tackled in priority order. (1) Crate versions bumped: keleusma 0.1.1 → 0.2.0, keleusma-bench 0.1.0 → 0.2.0, keleusma-cli 0.1.0 → 0.2.0, keleusma-macros 0.1.0 → 0.2.0; keleusma-arena unchanged at 0.3.0 (already on crates.io). Intra-workspace dep version requirements bumped to match. (10) MSRV review: 1.85 for arena/macros, 1.88 for keleusma/bench/cli. Recent additions (env::set_var unsafe in 2024 edition, let-chains in cost-model emit, libm::ceil) all within the pinned MSRV. (11) cargo doc clean: seven rustdoc warnings resolved — Vm::resume link fixed to crate path, sealed::HostOpaqueTypeId rendered as text not link, Op::CallNative replaced with the V0.2.0 split (CallVerifiedNative, CallExternalNative), Ctx::newtypes and Ctx::fresh rendered as prose, compute_chunk_wcmu retargeted at wcmu_stream_iteration, DwtCycCnt link removed (gated on target_arch). The one remaining warning is the known cargo issue #6313 collision between lib `keleusma` and bin `keleusma`. (7) Spec docs freshness: opcode count (69) matches Op enum; wire-format constants (BYTECODE_MAGIC, BYTECODE_VERSION=1, FLAG_REQUIRES_SIGNATURE=0x02) match between code and docs; negative IFC labels and signed-modifier surface present in GRAMMAR.md; signature extension layout present in WIRE_FORMAT.md. The stale "AArch64 produces degenerate one-cycle output" note from § 17.2 was rewritten to "resolved" in the prior session. (2) CHANGELOG.md V0.2.0 entry: the existing [Unreleased] block was already a comprehensive V0.2.0 changelog; promoted to versioned `[0.2.0] - 2026-05-21` and added a release headline summarising the headlines (signing, ISA reset, IFC labels, calibrated WCET, docs reorg, breaking changes). Fresh [Unreleased] section inserted above. (8) WHY_REJECTED audit: closure rejection diagnostic ("closures are not supported; V0.2.0 admits only direct calls and trait dispatch") matches src/typecheck.rs:3547; first-class function reference diagnostic ("first-class function references are not supported in V0.2.0") matches src/compiler.rs:3934. (9) README accuracy: top-level README's Cargo dep example bumped to "0.2"; the "V0.1.x" FAQ blurb softened to acknowledge V0.2.0's existence. All 380+ markdown cross-references in docs/ and project-root README.md continue to resolve. (13) Unsafe block audit: 97 unsafe sites across the workspace, of which the V0.2.0-introduced ones are six (RDTSC, CNTVCT_EL0, CNTFRQ_EL0, DWT_CYCCNT MMIO, env::set_var, ZeroSizeOk wrapper). All have inline SAFETY comments documenting the invariants. (4) Full workspace tests: 826 main keleusma lib tests + 53 rogue-script + 37 arena + 17 marshall + 17 zero_copy + 6 bench + smaller suites all pass under default features. The default+signatures combo also passes 826+ tests cleanly. `--no-default-features` required gating `benchmark_runs_to_completion` test on the `std` feature; now passes 826 main tests + 53 rogue-script + others. `--all-features` exposes 5 pre-existing test failures (embedded_8 target tests and checked-arithmetic high-half assertions) at unusual feature interactions; not in the publish-relevant configurations. (5) CI workflow review: .github/workflows/ci.yml covers check, test (default + no-default + signatures), clippy strict, fmt, MSRV per crate (1.85 arena, 1.88 keleusma), thumbv7em-none-eabihf no-std build, and Miri (stacked + tree borrows) on arena. Gaps noted but not blockers: keleusma-bench is not in CI; the N6 target (thumbv8m.main-none-eabihf) is not in CI (closest is thumbv7em); cargo doc is not in CI; SDL3-gated examples are skipped without the feature. (6) Examples build pass: `cargo build --workspace --examples --release` clean; `cargo build --workspace --examples --release --features sdl3-example` also clean (piano_roll, rogue). (12) N6 boot with WCET report: three-task-n6 with `keleusma-verify` flashed cleanly via probe-rs; defmt RTT captured the WCET boot report exactly as designed — task `led` shows NOMINAL 74 / MEASURED 409377 cycles, task `sensor` NOMINAL 66 / MEASURED 362878, task `heartbeat` NOMINAL 60 / MEASURED 326458. Kernel boots, scheduler enters loop, tasks dispatch, supervised restart fires on the faulty task. (3) cargo publish --dry-run final gate: keleusma-macros 0.2.0 dry-runs clean; keleusma-arena 0.3.0 reports "already exists on crates.io" (operator decides whether to bump to 0.4.0 for the post-0.3.0 changes); keleusma 0.2.0, keleusma-bench 0.2.0, keleusma-cli 0.2.0 fail dry-run with "candidate versions found which didn't match: 0.1.x" because the publish order requires bottom-up commits (macros first, then keleusma, then bench/cli). This is the standard cargo workspace publish dance, not a publishable-state issue. Final clippy strict pass clean; cargo fmt --check clean after one auto-format pass. Item 14 (migration guide) rejected per operator; item 15 (B15 Type::Unknown removal) under operator consideration; item 16 (tag/release process) premature. |
| 2026-05-21 | Measured cost-model fragments are now consumed by code, not just generated. The prior session's audit confirmed the committed `aarch64_apple_darwin.rs` and `thumbv8m_main_none_eabihf.rs` fragments were not referenced from any `.rs` file outside the bench crate. Closing the gap on three fronts. (A) Documentation patch. New cookbook section "Calibrated WCET with a measured cost model" in `docs/guide/COOKBOOK.md` walks through `include!` of the fragment, target dispatch via `cfg(target_arch = ...)`, and the `_with_cost_model` API variant call. The stale `docs/spec/GRAMMAR.md` note at section 17.2 about AArch64 calibration producing "everything is one cycle" was rewritten to "resolved"; the original bug is fixed and the current behaviour (CNTFRQ_EL0 read plus scale factor) is documented inline. New cross-reference subsection "Calibrated WCET in CPU cycles" added to `docs/guide/EMBEDDING.md` so the embedding guide points at the cookbook recipe and the measured-model fragments. (B) Standalone example. New `examples/measured_wcet.rs` (registered in workspace `Cargo.toml`) compiles a small Stream-classified program, calls `wcet_stream_iteration_with_cost_model` under both `NOMINAL_COST_MODEL` and `MEASURED_COST_MODEL`, and prints the comparison. On the dev host the example reports `NOMINAL 25 cycles, MEASURED 2145 cycles, ratio 85.80x` for the same chunk, consistent with the architectural M1 Max scaling. (C) Headline-example wiring. New `examples/rtos/src/cost_model.rs` exposes a target-dispatched `MEASURED_COST_MODEL` (M1 Max fragment on aarch64-apple-darwin, Cortex-M55 fragment on thumbv8m, NOMINAL fallback elsewhere) plus `report_measured_wcet(bytecode)` and `report_measured_wcet_from_source(source)` helpers. Both rtos demonstrator binaries log per-task WCET at boot under the `keleusma-verify` feature: `three-task-std` uses the source-compile path against the prelude-prepended task scripts; `three-task-n6` uses the precompiled-bytecode path. The std demonstrator output on the dev host shows realistic ratios (led 6214/74 = 84x, sensor 5528/66 = 84x, heartbeat 5006/60 = 83x, event_listener 3102/38 = 82x, faulty 5624/70 = 80x), consistent with the M1 Max measured-to-nominal scaling. `setup::PRELUDE` was promoted from private const to `pub` so the binaries can prepend the prelude when compiling task sources off-line. Both rtos builds clean: host std-platform (with and without keleusma-verify), N6 thumbv8m (with and without keleusma-verify). All 6 bench unit tests pass; workspace builds clean. |
| 2026-05-21 | `keleusma-bench` gains `--cpu-hz <Hz>` CLI flag. Operator can override the assumed CPU clock without setting an environment variable. The flag takes precedence over `KELEUSMA_BENCH_CPU_HZ` if both are present. In host-bench mode, the override propagates through `assumed_cpu_hz()` to the counter's `cpu_cycles_per_count` scaling, so the resulting fragment is calibrated for the supplied frequency. In `--from-log` mode, the override replaces the `BENCH_DONE`-reported `cpu_hz` field in the emitted fragment header; this lets operators on Cortex-M targets correct the documentation after capture without rebuilding the embedded binary (DWT_CYCCNT ticks at actual CPU clock by construction so cycle counts are unaffected by the documented value). The bench's stdout banner now reports the source of the CPU clock assumption (`--cpu-hz override`, `KELEUSMA_BENCH_CPU_HZ env var`, or `DEFAULT_ASSUMED_CPU_HZ`). Implementation uses `unsafe { env::set_var(...) }` because the 2024 edition marks `set_var` unsafe; the bench main is single-threaded at this point so the unsafe block is justified. New READMEs document the flag, the precedence with the env var, and the post-capture override workflow for embedded fragments. All 6 unit tests pass; the flag works on both paths end-to-end (host-bench scale changes from 134.5 to 125.0 when overriding 3.228 GHz to 3.0 GHz; from-log fragment header shows 400 MHz instead of 800 MHz when overriding the N6 log). |
| 2026-05-21 | N6-DK WCET table generated on hardware. The STM32N6570-DK was connected via probe-rs and the `bench_n6` binary flashed and run. First attempt with `BenchConfig::embedded_default` at 1,000 pattern repetitions and 64 KB arena triggered a heap fragmentation panic at the 6th spec (`Dup`); the linked-list allocator could not satisfy a fresh 64 KB arena allocation after five iterations of allocate-then-free cycles even with the `ZeroSizeOk` wrapper in place. Fix: added `arena_capacity` field to `BenchConfig` and reduced both the embedded defaults to 200 repetitions and 8 KB arena. The bench's runtime working set is tiny (the patterns leave the operand stack near empty); 8 KB is comfortable. At Cortex-M55 800 MHz with single-cycle DWT_CYCCNT resolution, 200 repetitions of patterns costing 3000-13000 cycles each still produce hundreds of thousands of cycles per measurement pass, which is plenty of resolution. Second attempt ran cleanly to completion: all 17 specs measured in 8.14 seconds wall time. Generated fragment committed at `keleusma-bench/measured_cost_models/thumbv8m_main_none_eabihf.rs`. Final measured per-category CPU cycles: data movement 6070, control marker 6070 (scaled nominal fallback), arithmetic/comparison/bitwise/casts 10079, division/field lookup/type checks 9164, composite construction 13540, function call 60700 (scaled nominal). The ratios vs the dev-host fragment (M1 Max at 3.228 GHz) are: data movement 70x, arithmetic 61x, composite construction 40x, consistent with the architectural difference between an out-of-order superscalar with deep caches (M1 Max) and an in-order Cortex-M55 running from flash. The fragment compiles cleanly as an `include!` target in a host crate; the probe verified each category returns the expected cycle count. The `measured_cost_models/README.md` table now lists both fragments with their counter and CPU-clock metadata. The `KELEUSMA_BENCH_CPU_HZ` env-var is irrelevant on Cortex-M because DWT_CYCCNT counts CPU cycles directly. |
| 2026-05-21 | Embedded WCET infrastructure for the STM32N6570-DK. Three pieces. (1) `keleusma-bench` lib refactored to no_std + alloc-compatible behind a `std` cargo feature (default). The lib now uses `alloc::collections::BTreeMap`, `alloc::string::String`, `alloc::vec::Vec`, and `libm::ceil` so the measurement primitives compile against `thumbv8m.main-none-eabihf`. The CLI bin (`required-features = ["std"]`) and the `KELEUSMA_BENCH_CPU_HZ` env-var override remain std-gated. The host build, all 6 unit tests, and the existing aarch64 measurement pipeline are unaffected. (2) New `BenchConfig` struct parametrises `repetitions`, `warmup_passes`, and `measurement_passes`; `BenchConfig::embedded_default()` uses 1,000 repetitions (versus the host's 100,000) so the constructed chunk fits in the N6's 384 KB RAM. New `benchmark_spec_with_config` and `measure_one_with_config` entry points consume the config. (3) New Cortex-M `DwtCycCnt` counter implementation in `keleusma-bench/src/counter.rs`. The counter reads DWT_CYCCNT via volatile MMIO at `0xE000_1004`; `cpu_cycles_per_count` returns 1.0 because DWT_CYCCNT ticks at CPU clock by construction; `frequency_hz` returns the CPU clock supplied at construction. New `examples/rtos/src/bin/bench_n6.rs` binary boots embassy, sets DEMCR.TRCENA and DWT.CTRL.CYCCNTENA via direct register pokes, constructs a `DwtCycCnt::new(800_000_000)`, runs each spec with `measure_one_with_config(_, _, BenchConfig::embedded_default())`, and emits each measurement as a single `BENCH idx=I/N name=NAME bits=BITS per_op=COST` defmt RTT line followed by `BENCH_DONE cpu_hz=HZ counter_hz=HZ`. The bits are the raw f64 bit pattern so the host runner can reconstruct the exact measurement without going through a lossy decimal text intermediary. Cross-compiles cleanly to thumbv8m.main-none-eabihf: text 128 KB, bss 132 KB (mostly the 128 KB heap-allocator backing store), fits comfortably in the 384 KB RAM budget. `keleusma-bench` CLI gains a `--from-log <path>` flag that parses a captured defmt log instead of running the host bench; the parser extracts BENCH/BENCH_DONE markers and reconstructs the f64 measurements from their u64 bit patterns, then runs the same `emit_cost_model_source` to produce a target fragment. Verified end-to-end against a synthetic 17-line log: 17 measurements parsed, fragment generated, scale factor 1.000, function-call category falls back to scaled-nominal (87× → 870 cycles) consistent with the dev-host fragment. Documentation: `keleusma-bench/README.md` describes the embedded path and the DwtCycCnt counter; `keleusma-bench/measured_cost_models/README.md` documents the N6 capture workflow (cargo run via probe-rs, tee log, keleusma-bench --from-log). The committed N6 fragment is deferred to a follow-on session when hardware is connected and the bench runs on the real board. The infrastructure is in place; the run-on-hardware step is the next natural step. All host tests pass; clippy and fmt clean. |
| 2026-05-21 | `keleusma-bench` counter-to-cycle scale fix. Operator flagged that VM opcodes reporting one pipelined cycle is implausible and identified a scale mismatch between the profiling counter and the WCET arithmetic. Diagnosis: on AArch64 (the development host is an Apple M1 Max), the bench reads CNTVCT_EL0 which ticks at 24 MHz (read from CNTFRQ_EL0 directly). One counter tick is approximately 134 CPU cycles at the M1 Max's 3.228 GHz P-core nominal. The bench was reporting raw counter ticks as if they were CPU cycles, understating by roughly two orders of magnitude. Fix: extended the `CycleCounter` trait with `cpu_cycles_per_count` and `frequency_hz` methods. `Rdtsc::cpu_cycles_per_count` returns 1.0 (invariant TSC counts CPU cycles directly). `CntvctEl0::cpu_cycles_per_count` reads CNTFRQ_EL0 at runtime and returns `assumed_cpu_hz / counter_hz`. `InstantFallback::cpu_cycles_per_count` returns `assumed_cpu_hz / 1_000_000_000`. New `DEFAULT_ASSUMED_CPU_HZ = 3.228e9` (M1 Max P-core nominal) with `KELEUSMA_BENCH_CPU_HZ` env var override for per-host calibration. `benchmark_spec` multiplies the raw counter delta by `cpu_cycles_per_count` before dividing across patterns, so the reported value is CPU cycles. The emitted fragment header records the counter name, the counter tick frequency, the assumed CPU clock, and the resulting scale factor. Second fix: the nominal fallback for unmeasured categories (`Yield`, `Call`) was in nominal relative-weight units (1, 10) while measured categories were in CPU cycles (hundreds), producing an incoherent mixed-unit model. Fallback now scales the nominal value by the maximum measured-to-nominal ratio across measured categories (87 for the M1 Max generation), keeping units consistent. Regenerated fragment shows realistic VM-dispatch costs: data movement 87 cycles, arithmetic 164 cycles, division 140 cycles, composite construction 338 cycles, control marker 87 cycles (scaled nominal fallback), function call 870 cycles (scaled nominal fallback). All 6 bench unit tests pass. The fragment compiles cleanly as an `include!` target. `keleusma-bench/measured_cost_models/aarch64_apple_darwin.rs` regenerated. `keleusma-bench/README.md` and `keleusma-bench/measured_cost_models/README.md` updated to document the scaling, the assumed CPU clock, and the `KELEUSMA_BENCH_CPU_HZ` override. The runtime is untouched; `NOMINAL_COST_MODEL` continues to default. Hosts that adopt `MEASURED_COST_MODEL` get CPU-cycle estimates appropriate for the documented host. |
| 2026-05-21 | `keleusma-bench` repair and first measured cost-model fragment for the development host. Two bugs found and fixed in the bench tool. Bug 1: the `OPCODE_SPECS` arithmetic patterns used `Op::Add` / `Op::Sub` / `Op::Mul` / `Op::Neg` with `Int` operands, which V0.2.0 Consolidation B narrowed to `Byte` / `Fixed` / `Float` only; on `Int` operands these opcodes now trap with `TypeError`. Replaced the four specs with `Op::CheckedAdd` / `Op::CheckedSub` / `Op::CheckedMul` / `Op::CheckedNeg` plus `Op::PopN(3)` (the checked opcodes push three values: low, high, flag). Removed the retired `Op::MakeClosure` spec entirely (closures were retired in V0.2.0 Phase 4). Bug 2: the cost-emit logic divided `cycles_per_pattern` by `ops_per_pattern` before rounding, which collapsed every category to 1 cycle on the AArch64 CNTVCT_EL0 counter because per-op fractional values land below one counter tick (the counter runs at 24 MHz on Apple Silicon, far below CPU clock). Switched to `ceil(cycles_per_pattern)` directly so relative ordering between categories is preserved at the cost of overstating per-op absolute cost (which is conservative for WCET). Diagnostic improvement: warmup-pass failures now surface to stderr and short-circuit the spec rather than silently reporting zero. Unmeasured categories (`Yield` cannot run in a Func chunk; `Call` requires a multi-chunk module the bench does not construct) now fall back to `nominal_op_cycles` values rather than to a placeholder push-and-pop pattern; without the fallback, function-call cost would have been dangerously optimistic at 1 cycle versus the nominal 10. Emit logic now lists every V0.2.0 ISA opcode across the six categories (previously missed `Checked*`, `BitAnd`/`Or`/`Xor`, `Shl`/`Shr`, `WordToByte`/`ByteToWord`, `WordToFixed`/`FixedToWord`, `FixedMul`/`FixedDiv`, `BoundsCheck`, `GetDataIndexed`/`SetDataIndexed`). Generated and committed `keleusma-bench/measured_cost_models/aarch64_apple_darwin.rs` for the development host (aarch64-apple-darwin). Final measured ratios versus nominal: data movement 1 versus 1, control marker 1 versus 1, arithmetic 2 versus 2, division 2 versus 3, composite construction 3 versus 5, function call 10 versus 10 (via nominal fallback). New `keleusma-bench/measured_cost_models/README.md` documents the fragment, the host architecture, the cycle counter and its calibration caveats, and how to include the fragment into a host crate. Main `keleusma-bench/README.md` updated with the methodology notes, the per-pattern-vs-per-op rationale, and the pre-generated fragments cross-reference. All 6 bench unit tests pass (`opcode_specs_have_balanced_stack_patterns` confirms the new `PopN(3)` patterns are balanced). The committed fragment compiles cleanly as an `include!` target. Workspace tests, clippy, and format unchanged from the prior session round; no source code in `keleusma` proper was touched. |
| 2026-05-21 | Roadmap and documentation pass for V0.3.0 through V0.5.0. New strategy docs: `docs/roadmap/V0_3_0_SELF_HOSTING.md` expanded with bootstrap procedure (Phase A cross-compile, Phase B self-compile, Phase C fixed point), inter-stage data shapes (Token, Declaration, CompiledChunk sketches), required surface-language features inventory, success criteria, risks-and-mitigations table, and incremental migration ordering (Lexer → Parser → Compiler) with per-step regression-corpus equivalence checks against the all-Rust baseline. New `docs/roadmap/V0_4_0_NATIVE_CODEGEN.md` covers LLVM as the code generation backend; the bytecode-as-verification-IR plus native-as-deployment-shape pattern; sub-coroutine lowering to LLVM coroutine intrinsics (switched-resume kind, custom arena allocator via `@llvm.coro.id.async`); static-library `staticlib` deliverable for Rust hosts; hot-replacement-friendly versus performance-friendly build modes (cross-module inlining suppression cost surfaced); best-effort WCET on native (bytecode is the verification artefact, native is a soft upper bound); three V0.5.0 refinements the V0.4.0 research surfaces; vintage-processor targets (6502 via out-of-tree llvm-mos, 68000 via upstream LLVM, Z80 via SDCC) framed as aspirational. New `docs/roadmap/V0_5_0_KELEUSMA_HOST.md` covers two driver shapes (`impure fn main` for CLI utilities, `impure loop main` for long-running drivers); three-mode purity discipline (`pure` default, `impure` for I/O, `transitive` for purity-polymorphic functions with pure body and impure-callable callbacks); file-based modules in the Modula-2 / Ada tradition with explicit interface declarations carrying declared WCMU and WCET bounds; declared sub-DAG arena partitions with master-WCMU-based allocation (dynamic and managed allocation explicitly rejected); structured live code update with interface-fingerprint enforcement following the Erlang/OTP model; four-phase bootstrap procedure (α cross-host bytecode, β self-host compiler, γ fixed point, δ migrate to native shape). New `docs/architecture/SUB_COROUTINES.md` preliminary spec for asymmetric (call-down / yield-up) sub-coroutines with arena-resident state (program counter plus call-frame stack plus operand stack plus arena slot all co-located in the slot); ephemeral versus persistent lifetime distinction framed around slot-reusability-at-completion rather than during-execution; spawn-time slot availability policies (static verification, runtime fallibility, compile-time rejection); new opcodes `SpawnCoroutine`, `ResumeCoroutine`, `ReleaseCoroutine` with explicit lowering to LLVM coroutine intrinsics in V0.4.0. Docs reorganization: new `docs/spec/` section consolidates the authoritative specifications previously scattered across architecture/, design/, and reference/; six files moved via `git mv` with history preserved: `design/GRAMMAR.md`, `design/TYPE_SYSTEM.md`, `design/STANDARD_LIBRARY.md`, `reference/INSTRUCTION_SET.md`, `architecture/WIRE_FORMAT.md` all moved into `spec/`; `reference/TARGET_ISA.md` renamed to `spec/STRUCTURAL_ISA.md` (old name was misleading; the file's own heading already read "Structural ISA"). `docs/design/` directory retired. `docs/architecture/` reframed as narrative descriptions of the implemented system. `docs/reference/` pruned to GLOSSARY plus RELATED_WORK. All 380 markdown cross-references in `docs/` validated to resolve; project-root README.md, CHANGELOG.md, and CLAUDE.md cross-references also updated. `docs/roadmap/PHASE_0_BOOTSTRAP.md` removed (status was internally contradictory: header said "In Progress" while all milestones said "Complete"; milestone definitions conflicted with TASKLOG.md which is the designated source of truth). Phase Overview table in `docs/roadmap/README.md` retired (stale relative to current strategy docs). `docs/DOCUMENTATION_STRATEGY.md` tree refreshed to match the actual filesystem (previously missed guide/, extras/, EXECUTION_MODEL.md, WIRE_FORMAT.md, SUB_COROUTINES.md); Finding Information table expanded. `docs/README.md` Quick Reference and Sections tables similarly refreshed. `CLAUDE.md` Sections table updated to include Guide, Spec, and Extras and to reflect the architecture/spec/reference reframing. No source code changed; previous round's tests, clippy, and example builds remain valid. |
| 2026-05-20 | V0.2.0 signed compiled modules. New `signatures` cargo feature (off by default) brings `ed25519-dalek 2`. Wire-format header extension through the existing `header_length: u16` field: bytes 64..72 carry the signature metadata block (scheme_id at 64, reserved at 65, signature_length LE at 66..68, reserved u32 at 68..72) and bytes 72.. carry the raw signature payload, padded to an 8-byte boundary. Ed25519 (scheme_id = 1) is the only V0.2.0 scheme; the wire format reserves the byte so future schemes (ECDSA, ML-DSA, LMS) ship without an ABI break. Surface keyword: `signed` modifier on the entry function declaration, admissible on any of `fn` / `yield` / `loop` and only on the entry function; helper functions with `signed` are rejected at compile time. The compiler sets `FLAG_REQUIRES_SIGNATURE = 0x02` in the module's header flags byte. Message convention: signature computed over the entire framed buffer with the signature payload bytes and the CRC trailer bytes zeroed; both signer and verifier reconstruct that view. New API: `wire_format::module_to_signed_wire_bytes(module, signing_key)`, `wire_format::verify_module_signature(bytes, &keys)`, `wire_format::parse_signature_metadata(bytes, header_length)`, `wire_format::header_requires_signature(bytes)`. New VM methods: `Vm::load_signed_bytes(bytes, arena, &keys)` (initial signed load), `Vm::replace_module_from_bytes(bytes, initial_data)` (signed hot-swap inheriting the trust matrix), `Vm::register_verifying_key`, `Vm::clear_verifying_keys`, `Vm::verifying_keys_len`. `Vm::new` rejects modules carrying `FLAG_REQUIRES_SIGNATURE` directly because the signature info is lost during decode; callers use `load_signed_bytes` or hot-swap. New `LoadError::InvalidSignature` and `LoadError::SignaturesUnsupported` variants. CLI: `keleusma compile script.kel --signing-key seed.bin -o out.bin` signs (when the source declares `signed`); `keleusma run out.bin --verifying-key key.pub` (repeatable) populates the trust matrix. R42 added to `docs/decisions/RESOLVED.md` with the design rationale; `docs/spec/WIRE_FORMAT.md` updated with the extension layout; `secret/SIGNATURE_SCHEME_MIGRATION.md` (gitignored, internal) records the migration trade-off matrix for future schemes. Tests: 814 lib (was 807, +7 wire-format + +6 vm signed-modules) all green with `--features signatures`; 807 lib all green without; clippy strict clean across `--all-features`; fmt idempotent. CLI smoke test exercises sign + verify-success + verify-wrong-key + verify-no-key end to end. STM32N6570-DK firmware re-flashed: unsigned-modules path unchanged, scheduler runs, supervised restart fires on the faulty task. |
| 2026-05-20 | Cross-architecture rkyv-decode regression on STM32N6570-DK fixed. `wire_format::module_from_wire_bytes` now copies the auxiliary-body subslice into a `rkyv::util::AlignedVec<8>` before calling `rkyv::from_bytes`, mirroring the alignment-copy pattern that the pre-V0.2.0-Phase-7c `Module::from_bytes` used. Without the copy, `rkyv::from_bytes` (which calls `rkyv::access` internally) rejected the unaligned subslice on the 32-bit ARM target with the opaque "failed without error information" message from rancor; on x86_64 the input happened to land at a usable alignment so the failure mode was masked. Regression introduced in V0.2.0 Phase 7c (593f541) which cut `Module::from_bytes` over to the wire-format reader without porting the AlignedVec step. The owned-decode contract of `view_bytes` and `from_bytes` is now uniform: both paths tolerate arbitrarily aligned input through the AlignedVec copy. The zero-copy alignment requirement is preserved by `Module::access_bytes` and `Vm::view_bytes_zero_copy`, which still check `aux_body.as_ptr() % 8 == 0` and reject unaligned input. The previously-passing `bytecode_view_bytes_rejects_unaligned_input` test (which encoded the legacy contract) is rewritten as `bytecode_view_bytes_handles_unaligned_input` and asserts the new tolerance plus round-trip soundness through `decoded.entry_point.is_some()` and `decoded.word_bits_log2 == module.word_bits_log2`. Hardware verification on STM32N6570-DK: `three-task-n6 --no-default-features --features stm32n6570dk-platform` and `--features stm32n6570dk-platform,keleusma-verify` both boot, load all five precompiled tasks (led, sensor, heartbeat, event_listener, faulty), enter the scheduler loop, and exercise the supervised-restart path on the faulty task. Workspace tests: 956 across 16 suites, all green; clippy strict clean; fmt idempotent. |
| 2026-05-20 | Pre-merge documentation-sync pass. `docs/spec/INSTRUCTION_SET.md`: opcode count corrected from 65 to 69 (and the operand-shape inventory's `None` row from 38 to 36), inline-vs-pool split corrected to 65/4 (was 58/7), per-instruction WCET cost column realigned with `nominal_op_cycles` across CheckedAdd/Sub/Mul/Div/Mod (3-4 → 2), Neg (1 → 2), BoundsCheck (1 → 2), If/BreakIf (2 → 1), Call/CallVerifiedNative/CallExternalNative (5 → 10), Yield (5 → 1), Reset (4 → 1), NewStruct/NewEnum/NewArray/NewTuple (3 → 5), GetField (2 → 3), GetIndex (3 → 2), IsEnum/IsStruct (2 → 3), WordToByte/ByteToWord (1 → 2), FixedMul/FixedDiv (4 → 2). Cost Summary regenerated. Stack growth/shrink tables rebuilt from `Op::stack_growth` and `Op::stack_shrink`. `docs/architecture/EXECUTION_MODEL.md`: wire-format mislabelled as V0.3.0 (now V0.2.0), framing-header byte-offset table rewritten to match `WIRE_FORMAT.md`'s canonical layout (header length at bytes 6..8, total length at bytes 8..12, shared/private data at bytes 24..32, etc.), inline `(u16, u8)` shape now correctly described as inline rather than pool-referencing, pool-using shapes' encoding documented as 24-bit pool index, operand-pool entry tag table corrected to two values (0x01 and 0x02). Guide and design docs: `README.md`, `docs/spec/GRAMMAR.md`, `docs/architecture/LANGUAGE_DESIGN.md`, `docs/spec/STANDARD_LIBRARY.md`, `docs/guide/EMBEDDING.md`, `docs/guide/COOKBOOK.md`, `docs/guide/WHY_REJECTED.md`, and `docs/decisions/BACKLOG.md` B3/B5b/B6 entries lost references to the retired f-string surface, the retired `text` cargo feature, the retired `stddsl::Text` bundle, the retired bundled text-composition natives (`to_string`, `concat`, `slice`, `length`), the retired closure-hoisting compiler pass, and the retired `Op::CallIndirect` / `Op::PushFunc` / `Op::MakeClosure` / `Op::MakeRecursiveClosure` opcodes. Closure rejection is now consistently described as a type-checker-stage diagnostic. Surface examples now use `Text` rather than `String`. The pass touched only `*.md` files; no source code changed, so the prior round's test, clippy, and example-build results remain valid. |
| 2026-05-20 | V0.2.0 ISA Phase 8 cleanup follow-on. Repository hygiene: new `.gitignore` entry for `*.kel.bin` (artefacts go stale across V0.2.x patch releases as the wire format iterates); retired `examples/zero_copy_demo.kel.bin` and `examples/regenerate_zero_copy_bytecode.rs`; rewrote `examples/zero_copy_include_bytes.rs` to compile through `include_str!` at runtime, demonstrating zero-copy execution against an `AlignedVec<8>` populated from a freshly compiled module. New R41 rejects the five-opcode dynamic-string-builder proposal (`BuildKStr`, `KStrAppendStatic`, `KStrAppendInt`, `KStrAppendFloat`, `KStrAppendBool`, `KStrFinalize`); rationale: dispatch-table cost vs host responsibility, WCMU bound looseness, opcode-count target conflict; recommended path is a host `format` native returning `Value::KStr`. Open concerns closed: (1) Live soft-warning trigger test: extracted `compiler::check_chunk_size_against_limits` from the inline compile-function check; three new tests directly exercise the helper at threshold + 1, hard cap + 1, and exactly at threshold. (2) Narrow-bytecode `CheckedXxx` flag and high half: replaced the per-arm computation with `vm::checked_arith_outputs::<W>(r: W::Wide, word_bits_log2: u8) -> (W, W, W)` using `WideWord` operations only (no `i128` literals); flag fires at declared range; high half computed as `(r - low_widened) >> declared_bits` so `(high, low)` reconstructs the true result; nine new unit tests across runtime-width and declared 32 / 16 / 8 -bit paths plus the reconstruction invariant. Removed the now-unused `declared_width_range` helper from `src/bytecode.rs`. Workspace tests: 797 lib + 53 rogue-script + 17 marshall, all green; clippy strict clean across `--all-features`; examples clean; RTOS host bin clean. |
| 2026-05-20 | V0.2.0 ISA Phase 8: documentation alignment and publication readiness. `BYTECODE_VERSION` confirmed at 1 in `src/bytecode.rs`. `Archive`, `Serialize`, `Deserialize` derives dropped from `Module`, `Chunk`, and `Op` now that the wire-format codec is the sole serialization path; `ArchivedModule`, `ArchivedChunk`, and `ArchivedOp` types are no longer generated. User-facing docs refreshed: the FAQ "Strings" section retired the `text` cargo feature, the f-string interpolation surface, and the bundled `to_string` / `concat` / `length` / `slice` natives; rewrote the static-string escape table without `\{` / `\}`. The COOKBOOK "Working with Text" section follows the same shape. The FAQ "Closures" entry and the WHY_REJECTED.md "Recursive closure" / "CallIndirect" entries point at the type-checker-stage rejection diagnostic introduced in Phase 4 rather than the legacy load-time verifier path. The EMBEDDING "Bundled Natives" section updated to reflect `register_utility_natives` shrinking to just `println`. Stale `piano_roll_*.kel.bin` fixtures deleted from `examples/scripts/piano_roll/`. Workspace tests: 785 lib + 53 rogue-script + 17 marshall + 699 no-floats lib tests pass; clippy strict clean; examples clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Phase 7c: cut the default `Module::to_bytes` / `Module::from_bytes` / `Module::access_bytes` over to the wire format. `Module::to_bytes` delegates to `wire_format::module_to_wire_bytes`; `Module::from_bytes` delegates to `wire_format::module_from_wire_bytes`; `Module::access_bytes` validates the wire format and returns `&ArchivedWireAuxBody`. Vm's `archived()` returns `&ArchivedWireAuxBody` and reads the aux body offset from the wire-format header; `decode_all_ops` walks the opcode stream + operand pool sections through `wire_format::parse_wire_sections` and `decode_op_stream`. `chunk_op_count` reads `op_record_count` from the WireChunk metadata. `verify_native_classifications` walks `self.decoded_ops` instead of archived chunk ops. The VM's `view_bytes_zero_copy` reads target widths at byte offsets 12/13/14 (V0.2.0 layout) and consults the archived auxiliary body for the data segment slot counts. Decoder reorders width validation before the header-vs-aux cross-check so a patched-only-header byte still surfaces as `WordSizeMismatch` / `AddressSizeMismatch` rather than a Codec error. Retired the legacy 32-byte framing header constants (`HEADER_LEN`, `HEADER_WCET_OFFSET`, `HEADER_WCMU_OFFSET`, `HEADER_SHARED_DATA_OFFSET`, `HEADER_PRIVATE_DATA_OFFSET`, `FOOTER_LEN`), the legacy `CRC32_RESIDUE` constant, the legacy `strip_shebang_prefix` helper, and the `op_from_archived` conversion. Refreshed `bytecode_golden_bytes_for_main_returning_one` to the V0.2.0 byte sequence (216 bytes total, 8-byte opcode stream, empty operand pool). Regenerated `examples/zero_copy_demo.kel.bin` from 316 to 324 bytes; bumped the `BYTECODE_LEN` constant in `zero_copy_include_bytes.rs`. The `bytecode_admits_narrower_word_size` test now goes through `compile_with_target(Target::embedded_16())` so the header and aux body agree on the declared word width. Three test imports of `ArchivedModule` retired (now `crate::wire_format::ArchivedWireAuxBody`). Workspace tests: 785 lib + 53 rogue-script + 17 marshall + 699 no-floats lib tests pass; clippy strict clean; examples clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Phase 7b: parallel-route Module codec through the section-partitioned wire format. New `wire_format::WireChunk` and `wire_format::WireAuxBody` rkyv-archived types separate chunk metadata (and pointers into the opcode stream) from the chunk ops themselves. New `wire_format::module_to_wire_bytes(&Module) -> Result<Vec<u8>, LoadError>` encodes a full Module: 64-byte framing header, opcode stream as 4-byte records, operand pool as 8-byte entries, rkyv-archived auxiliary body, CRC-32 trailer. New `wire_format::module_from_wire_bytes(&[u8]) -> Result<Module, LoadError>` validates the framing, reads each section, deserializes the auxiliary body, decodes each chunk's ops from its opcode stream span, and reconstructs the Module. The decoder cross-checks header-mirrored fields against the auxiliary body and rejects disagreement as LoadError::Codec. Nine new round-trip and error-path tests cover empty modules, minimal programs, branchy programs (If/Else/Loop/EndLoop), pool-using programs (NewEnum/IsEnum/GetDataIndexed/SetDataIndexed), Stream chunks, plus BadMagic, BadChecksum, Truncated, and shebang paths. The default `Module::to_bytes` / `Module::from_bytes` / `Module::access_bytes` continue to route through rkyv pending the Phase 7c cutover. Fixed an inherited test failure: `target::tests::host_target_admits_floats_and_strings` is now gated on `feature = "floats"` and a parallel `host_target_admits_strings_without_floats` covers the same admissibility surface in the no-floats build. Workspace tests: 785 lib (was 776: +9 wire-format round-trip) + 53 rogue-script + 17 marshall + 699 no-floats lib, all green; clippy strict clean; examples build clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Phase 7a: wire format specification and types. New `docs/spec/WIRE_FORMAT.md` documents the 64-byte framing header layout, the 4-byte fixed-size opcode records with parity, the 8-byte operand pool entries with type tag and parity, and the section-partitioned body. New `src/wire_format.rs` module ships the types: `WireFormatHeader` (the 64-byte header layout), `OpcodeId(u8)`, `OpcodeRecord([u8; 4])`, `OperandPoolEntry([u8; 8])`, and the canonical opcode-id table mapping every Op variant. Encoder `encode_op(&Op, &mut Vec<OperandPoolEntry>) -> Result<OpcodeRecord, WireFormatError>` and decoder `decode_op(OpcodeRecord, &[OperandPoolEntry]) -> Result<Op, WireFormatError>` round-trip every opcode shape. The execution loop, `Module::to_bytes`, and `Module::from_bytes` continue to route through rkyv until Phase 7b cuts over; Phase 7c removes rkyv from the execution path. External-native chunk-level WCMU integration (Phase 5 concern follow-on): new `verify::NativeIterationBound` plus `module_wcmu_with_bounds` and `verify_resource_bounds_with_bounds` entry points that sum verified natives' per-call WCMU over static call sites and apply external natives' `max_invocations_per_iteration * per_call_wcmu_bytes` once per chunk via a unique-callee walk. VM `verify_resources` and `auto_arena_capacity` route through the new API via a new private `native_iteration_bounds` helper. Workspace tests: 776 lib (was 759: +14 wire-format, +3 bounds tests) + 53 rogue-script + 17 marshall, all green; clippy strict clean; examples build clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Phase 6: control-flow operand narrowing. The six block-structured control-flow opcodes (`Op::If`, `Op::Else`, `Op::Loop`, `Op::EndLoop`, `Op::Break`, `Op::BreakIf`) carry `u16` jump targets instead of `u32`. Compiler emits a hard `CompileError` for any chunk exceeding `u16::MAX` ops (65,535) and a `CompileWarning` at 80% of the cap (52,428 ops). Two new public items: `pub struct CompileWarning { message, chunk_name }` and `pub fn compile_with_warnings(program, target) -> Result<(Module, Vec<CompileWarning>), CompileError>`. `compile` and `compile_with_target` delegate to `compile_with_warnings` and discard the warnings. The cast in `FuncCompiler::patch_jump` narrows to `u16`; the post-emit hard-cap check guarantees the cast never truncates an admissible chunk. Phase 5 concern follow-on: `register_*` methods now deduplicate by name (the prior `natives.push` would have shadowed earlier entries through the dispatch `find` lookup); a re-registration replaces the previous entry rather than appending. The cache invalidation already in place ensures the load-time classification check re-runs after dedup. Five new tests: `chunk_size_thresholds_are_consistent`, `small_chunk_produces_no_warnings`, `duplicate_native_registration_replaces_prior_entry`, `duplicate_native_registration_swaps_classification`, plus the lib tests count increased from 755 to 759. Workspace tests: 759 lib + 53 rogue-script + 17 marshall, all green; clippy strict clean; examples build clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Phase 5 open-concern follow-up. The per-dispatch classification check is replaced by a lazy load-time check at the entry of `Vm::call_function`. New `Vm::verify_native_classifications(&mut self)` walks every native-call site in the loaded module and verifies the bytecode-declared classification matches the registered classification. The result is cached on the Vm; any `register_*` method or `replace_module` invalidates the cache. The dispatch arm in the run loop no longer performs the per-call comparison; the load-time check is the source of truth. The host may invoke `verify_native_classifications` explicitly after registration to surface mismatches at deployment validation. External-native WCMU contribution is now explicitly zeroed at the `verify_resources` / `auto_arena_capacity` handoff regardless of any `set_native_bounds` override: the chunk-level integration (`max_invocations_per_iteration * per_call_wcmu` per chunk) is forward-looking; the current handoff guarantees neither under- nor over-counting through the per-site sum. Three new tests cover the load-time path (`classification_mismatch_detected_before_execution`, `verify_native_classifications_callable_before_first_call`, `verify_native_classifications_idempotent`). Workspace tests: 755 lib + 53 rogue-script + 17 marshall, all green; clippy strict clean; examples build clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Phase 5: native ABI split. The source-level `use external module::name` syntax is parsed; the lexer gains an `external` keyword. The compiler emits `Op::CallVerifiedNative` for `use module::name` imports and `Op::CallExternalNative` for `use external module::name`. The legacy `Op::CallNative` opcode is retired from the Op enum, the rkyv ArchivedOp, the cost model, the VM dispatch, and the verifier's WCMU walk. Host registration gains `Vm::register_verified_native(name, fn, wcet, wcmu_bytes)` and `Vm::register_external_native(name, fn, max_invocations_per_iteration)`; the pre-existing `register_native` / `register_fn` paths continue to ascribe the verified classification. The `NativeEntry` struct gains a `classification: NativeClassification` field and a `max_invocations_per_iteration: Option<u32>` attestation; the VM's call-site dispatch cross-checks the registered classification against the opcode and rejects mismatches as `VmError::VerifyError`. Op enum count goes from 70 to 69. Golden-bytes test updated for the new archived-op tag. Five new tests: parser positive (`parse_use_external`, `parse_use_external_wildcard`); VM round-trip (`external_native_round_trip`); two classification-mismatch rejections (`native_classification_mismatch_rejected_at_call`, `external_classification_mismatch_rejected_at_call`). Workspace tests: 752 lib + 53 rogue-script + 17 marshall, all green; clippy strict clean; examples build clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Phase 4: closure opcode removal. The four closure opcodes (`Op::PushFunc`, `Op::MakeClosure`, `Op::MakeRecursiveClosure`, `Op::CallIndirect`) and the `Value::Func` runtime variant are removed from the bytecode and runtime. The closure-hoisting compiler pass is retired. The type checker now rejects `Expr::Closure` directly with a diagnostic naming the construct ("closures are not supported; V0.2.0 admits only direct calls and trait dispatch"). The compiler additionally rejects first-class function references (`Expr::Ident` resolving to a top-level function in a non-call position) and call-a-local invocations (`Expr::Call` on a local variable). The verifier's pre-emptive rejection loop for `MakeRecursiveClosure` and `CallIndirect` is removed because the opcodes no longer exist. Op enum count goes from 74 to 70. Golden-bytes test updated to reflect the smaller archived-op tag. Eight closure-typecheck tests, one compiler closure-span test, and two verifier closure-rejection tests retargeted at the typecheck-stage rejection path. Workspace tests: 747 lib + 53 rogue-script + 17 marshall, all green; `cargo clippy --tests --all-targets -- -D warnings` clean; `cargo build --examples` clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-20 | V0.2.0 ISA Consolidation B follow-up. Compiler routes `Int` arithmetic through `CheckedAdd` / `CheckedSub` / `CheckedMul` / `CheckedNeg` followed by `PopN(2)`; the VM-level dispatch for `Op::Add`, `Op::Sub`, `Op::Mul`, and `Op::Neg` drops the `Int` arm and now serves `Byte`, `Fixed`, and `Float` operand types only. Inference at the `BinOp` / `UnaryOp` dispatch defaults to `Word` (Int) when the compiler's partial `infer_expr_type` cannot resolve a type, so host-native return values and chained data-segment accesses route through the checked family. Additional inference cases: `Expr::TupleIndex`, `Expr::TupleLiteral`, and a recursive `FieldAccess` arm in `struct_name_of` so nested struct or data-block field paths resolve to their declared types. Compile-time generation of the wrapping-arithmetic synthesis is also applied to compiler-internal sites (array-indexing stride / offset arithmetic and for-loop counter increments). Narrow-bytecode-on-wide-runtime preserved through a new `truncate_int_to_declared_width` helper applied to the `low` half of every `CheckedXxx` dispatch; the `flag` and `high` halves remain relative to the runtime word width pending a follow-up narrow-width overflow-detection pass. Workspace tests: 750 lib tests, 53 rogue-script tests, 17 marshall tests, all green; `cargo clippy --tests --all-targets -- -D warnings` clean; `cargo build --examples` clean; STM32N6570-DK full pipeline release build clean. |
| 2026-05-19 | STM32N6570-DK hardware verification of the V0.2 image. After the AXISRAM2 rebalance (FLASH 640 KB → 704 KB, RAM 384 KB → 320 KB, HEAP_SIZE 320 KB → 256 KB) all three feature modes link and the full-pipeline binary runs end to end on the board. LED toggling observed; defmt RTT logs render through the new event-code path without `format!`-pulled symbols. Six new BACKLOG items recorded: B13 refinement-type compile-time elision through range analysis, B14 CallIndirect flow analysis (deferred to V0.3), B15 remove `Type::Unknown` entirely (B1 follow-up), B16 target-scaled `Fixed` defaults for sub-64-bit native runtimes, B17 embassy feature trimming, B18 big-number arithmetic worked example using the pattern-arm form. |
| 2026-05-19 | Pattern-matched checked-arithmetic arms with `(h, l)` bindings and match-arm guards. The numeric-overflow construct's arms are now pattern matches: `ok(p)` binds the in-range result, `overflow(h, l)` and `underflow(h, l)` bind the high and low halves of an `i128` intermediate. Patterns admit `_` (wildcard), bare identifier (binds), or signed integer literal (equality). An optional `when expr` guard between the pattern and `=>` falls through to the next arm when false. Exhaustiveness shifts from "exactly one of each outcome" to "each outcome's last covering arm is an unguarded catch-all". The pipe-combined `overflow|underflow => body` form is removed. Match expressions in general gain optional `when expr` guards via `MatchArm::guard: Option<Expr>`; exhaustiveness treats guarded arms as non-catch-all regardless of pattern shape. Bytecode stack effect on `Op::CheckedAdd/Sub/Mul` is now `pop 2, push 3 (high, low, flag)`; on `Op::CheckedNeg` it is `pop 1, push 3`. The runtime computes the true result in `i128` to derive `(high, low, flag)`. Compiler dispatch is a virtual loop over arms mirroring `match` lowering. Migration: every existing checked-construct site rewrites `overflow => body` to `overflow(_, _) => body` and `underflow => body` to `underflow(_, _) => body`. Three new match-guard tests, six new checked-arithmetic pattern tests. 642 lib tests pass workspace-wide. GRAMMAR.md, LANGUAGE_DESIGN.md, MANUAL.md Section 5.5, microkernel heartbeat script all updated. |
| 2026-05-19 | Refined-newtype saturation contracts (closes Item 2 of the V0.2 gap list). Newtype declarations accept an optional `with saturate_max = N, saturate_min = M` clause. The `saturate_max` and `saturate_min` keywords inside a numeric overflow construct are now context-determined: the type checker maintains an expected-type stack (pushed by annotated `let` bindings and by function return types) and, when the top is a refined newtype declared with the matching clause, the keyword is mutated in place to a constructor call against the declared literal. The refinement predicate is verified at runtime on the literal exactly as for any other constructor invocation. Legacy `Word::MAX` / `Word::MIN` semantics remain for the `Word` context. Implementation: `NewtypeDef` AST fields, parser `with` clause with signed-int literals, `Ctx::newtype_saturate_max` / `Ctx::newtype_saturate_min`, `Ctx::expected_type_stack`, AST-mutating `type_of_expr` / `type_of_block` / `check_stmt` / `check_function` signatures. Three new VM-level tests (`saturate_keywords_resolve_to_newtype_contract_via_function_return`, `saturate_keywords_resolve_to_newtype_contract_via_let_annotation`, `saturate_keywords_fall_back_to_word_extrema_without_newtype_context`). 637 lib tests pass. `docs/spec/GRAMMAR.md` Section 7.5 EBNF and `docs/architecture/LANGUAGE_DESIGN.md` Section "Surface Extensions Added in V0.2" updated. |
| 2026-05-19 | Microkernel production patterns (Items 1, 2, 4, 6 of the design discussion). Per-task WCET budget admission control on load and hot swap. Per-task supervised restart on `VmError::Halt` through `Vm::reset_after_error`. `Platform::feed_watchdog()` hook (default no-op) called every scheduler iteration. Kernel event queue with `post_event` and an internal `enable_event_tick` ticker; tasks wait through `yield (2, event_id)`. Two new demonstrator tasks (`event_listener`, `faulty`). Bare-metal `.text` on STM32N6570-DK grew by ~3 KB to 140 KB trust-load and 160 KB precompile-plus-verify; FLASH headroom for user code and NPU weights is now 480-500 KB. 622 lib tests pass workspace-wide. |
| 2026-05-19 | `floats` cargo feature gated. Surface support for `Float`, float literals, `Value::Float`, `ConstValue::Float`, the `audio_natives` and `stddsl` modules, `KeleusmaType for f64`, and the f64 arms in `Vm::binary_arith` and `compare_op` is now feature-gated. With the feature off, soft-float `compiler_builtins` routines (`__divdf3`, `__adddf3`, `__muldf3`) drop entirely. `Op::IntToFloat` and `Op::FloatToInt` discriminants stay defined to preserve wire-format stability; bodies return `VmError::InvalidBytecode` when the feature is off. Microkernel disables the feature; bare-metal STM32N6570-DK `.text` falls to 137 KB trust-load (was 149) and 157 KB precompile-plus-verify (was 169). FLASH headroom for user code and NPU weights grows to 483-503 KB out of 640. 622 lib tests pass with default features; 494 lib tests pass with `--no-default-features --features compile,verify`. |
| 2026-05-19 | V0.2 design-decision pass items 3, 4, 6, 7 plus flash savings (B, C, I). Item 3: bare `Option::None` type-checker tightening admits `Option<T> { Option::None }` returns. Item 4: native function signatures on `use` declarations (`use host::name(T1, T2) -> R`) validate parameter arity, types, and return type at call sites; microkernel prelude updated with signatures for all 17 host natives. Item 6: strict schema-hash check on `Vm::replace_module` (CRC-32 of slot name + visibility); escape hatch `Vm::replace_module_unchecked`. Item 7: `VmError::category` method with `Halt`/`SoftScript`/`SoftHost`. Microkernel kernel-error path uses category codes instead of `format!("{:?}", e)`, eliminating ~32 KB of float-formatter machinery. Release profile gains `panic = "abort"`. Bare-metal `.text` on STM32N6570-DK falls to 149 KB trust-load (was 180) and 169 KB precompile-plus-verify (was 199); FLASH headroom for user code and NPU weights grows to 471-491 KB out of 640. 622 lib tests pass workspace-wide (was 614; +1 Option::None positive, +1 VmError::category, +5 native-signature tests, +2 hot-swap tests, with 3 existing hot-swap tests rewritten). |
| 2026-05-19 | V0.2 deferred-items pass. Target-scaled `Fixed` defaults thread through the type checker (`check_with_target`) and the compiler (new `normalize_fixed_defaults` AST pass) so cross-compilation to 32-bit and 16-bit targets picks up Q15.16 and Q7.8 without explicit `Fixed<N>`. RTOS microkernel drops the `text` feature, replaces `host::log(text)` with `host::log_event(code, data)` forwarding to `Platform::log_event`, removes `register_utility_natives` and the embassy `exti`/`unstable-pac` features. Bare-metal `.text` on the STM32N6570-DK falls to 180 KB trust-load (was 192) and 199 KB precompile-plus-verify (was 211). README gained a feature-matrix table. 613 lib tests pass workspace-wide (was 611; +2 new tests for Fixed-default scaling). |
| 2026-05-19 | V0.2 Phase 8: struct and enum const initializers, per-yield arena dataflow refinement. `ConstInitializer` AST gained `Struct { name, fields }` and `Enum { enum_name, variant, args }` variants. Parser recognises both shapes inside const initializer position. Compiler validates the type name against the declared field type and falls back to permissive inner recursion when the precise inner type cannot be determined from the surface context. Text-size abstract interpretation pass gained a `yields_text` field on `ChunkTextAnalysis` and a public `verify::module_chunk_text_analyses` helper. Compiler ephemerality check now consults the entry chunk's per-yield/return analysis: declared `Text` return is only disqualifying when the entry chunk's compiled body actually leaves a text value on top of the abstract stack at a boundary-crossing op. 611 lib tests pass with `--features text` (was 609; +2 new tests for struct/enum initializers, +1 negative test for the dataflow refinement, +1 direct unit test of `module_chunk_text_analyses`). Workspace clippy clean. |
| 2026-05-16 | Operator clarifications. Untyped parameters are now inferred from context (typechecker writes resolved primitive types back into the AST); the earlier parser-level rejection is reverted. Multi-headed entry points compile for all three categories including `loop main(...)` via Op::Loop+Break wrapper around the dispatch. Duplicate function heads continue to be rejected uniformly. 520 lib tests pass with `--features text` (+10 over previous baseline). |
| 2026-05-16 | V0.2 reviewer's final ten-item list addressed. Lex error on integer overflow, compile error on duplicate `fn` and dead literal pattern heads, `Vm::new` rejection for modules without an entry point, `VmError::NotSuspended` for premature resume, source spans on structural-verification errors. FAQ entries document the lexical productivity rule and the intentional integer-wrap arithmetic. 510 lib tests pass with `--features text` (was 506; +4 new tests). Workspace clippy clean. |
| 2026-05-10 | `keleusma-arena 0.2.0` and `keleusma-macros 0.1.0` published to crates.io. `keleusma 0.1.0` ready; awaits manual `cargo publish`. Process-file compaction pass before main-crate publication. |
| 2026-05-10 | Pre-publication polish (T48–T52). Rustdoc warnings cleared, `Module` re-exported from crate root, root `CHANGELOG.md` added, CI MSRV split per-crate, no_std build verified against `thumbv7em-none-eabihf`. `KString` moved from `keleusma-arena` to a new `keleusma::kstring` module so the allocator crate retains only the generic `ArenaHandle<T>` mechanism. `keleusma-macros` gained LICENSE, CHANGELOG, and expanded documentation. Arena bumped to 0.2.0 with the additive epoch surface; sibling crates updated to depend on `"0.2"`. |
| 2026-05-10 | Cost-model calibration tool, standalone CLI, onboarding docs, SDL3 audio example with hot code swap (T39–T47). New workspace members `keleusma-bench` and `keleusma-cli`. New `docs/guide/` section. New `examples/piano_roll.rs` feature-gated under `sdl3-example`. |
| 2026-05-09 | V0.1-M3 development sweep (T1–T38). Type checker, host-owned arena, generics, closures, monomorphization, target descriptor, conservative-verification stance and compile-time enforcement. |
| 2026-05-08 | `keleusma-arena 0.1.0` published to crates.io. Pre-publication polish for the standalone allocator: drop-impl audit, miri stacked-borrows and tree-borrows verification, `mixed_allocator` example, CHANGELOG in Keep a Changelog format. |
| 2026-05-08 | V0.1-M1 precompiled bytecode wire format with CRC trailer, length and target widths in header (R39). V0.1-M2 rkyv format and zero-copy execution against borrowed archived bytecode (R40). |
| 2026-05-08 | V0.0-M6 arena allocator, WCMU instrumentation, native attestation, auto-arena sizing, bounded-iteration loop analysis (R34–R38). |
| 2026-05-08 | V0.0-M3 through V0.0-M5: data segment, hot swap API, cargo workspace, marshalling layer, two-string discipline (R24–R33). |
| 2026-05-08 | V0.0-M2 for-in arrays, tuple literals, utility natives, formal related-work pass with citations across knowledge graph. |
| 2026-05-08 | V0.0-M1 productivity verification and WCET analysis (R22–R23). |
| 2026-03-02 | Crate extracted from Vows of Love and War workspace. Knowledge graph created. Block-structured ISA transition (R22). |