diff --git a/CHANGELOG.md b/CHANGELOG.md index dccc868bd..772923619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,123 @@ All notable changes to EigenScript are documented here. ## [Unreleased] +## [0.47.0] - 2026-10-25 + +### Breaking changes + +- **Upgrading from 0.46.0:** four announced changes need code changes in some programs: the `rm` builtin is removed (use `remove_file`, #1884); removing a missing file raises `io` (#1668); tape format v7 records loaded module source as `load_file_source`/`load_file_source_chunk`, so a check that a tape holds only argv must allow them; and the observer predicates `improving` (#1771) and `equilibrium` (#1891) changed. The per-consumer table is in `docs/release-reviews/v0.47.0.md` (#1938). + +### Added + +- `make observer-oracle` scores the observer against a corpus graded by mathematics (Hardy, NIST 6.4.4.2) and by stated conventions (numpy `isclose`, Keras `mode=min`, settling time), decided on #1754. Each predicate is scored against one question (at a NaN checkpoint, the #1758 NaN convention); the labels are derived from per-sequence properties that `certify.py` certifies offline with sympy on the values the runtime is fed. Every row runs as module-level code (`x` a name) and as a loop (`x` a slot local) under the interpreter, the default JIT and forced OSR, and every run's bytecode listing must show the path its arm grades. A jit-tier run must witness that every iteration ran natively; an osr-tier run witnesses its last iteration only (earlier ones: #1768); a run that bails on an inf, NaN or clamped value counts as interpreted. Predicate reads always run interpreted. Rows that need IEEE inf/NaN or exact int64 values (derived from their values) run where one probe finds the capability (`EXPECT=ieee,int64` makes an absent one fail). A FINDING (any reading that differs between arms) or a wrong verdict on such a row fails the run, and so, by default (`FLOOR=` skips it), does any verdict lost against the v0.46.0 tag in `tools/observer_oracle/floor.json`, re-measured on the binary `tools/observer_oracle/build_anchor.sh` builds, or reuses, in the user cache; the floor is identified by the recipe and its verdicts, not the binary's bytes (#1746, #1758, #1764). The required CI check `observer oracle (floor)` runs it on every code change, against an anchor it builds itself under `env -i` in a digest-pinned image. A gate self-test (`plants.py --selftest`, run when the oracle changes) proves that the floor reports a reversed reading for every predicate, class and label direction as lost (#1764, #1778). On the reference model, distance beats entropy as the signal (#1667). + +### Changed + +- `read_text`, `read_bytes`, and `read_bytes_buf` now raise catchable `io` + errors containing the path and operating-system reason instead of returning + an empty failure sentinel. +- File writes, removal, rename, directory creation, and directory listing now + follow the same contract; fixed-cap text/list readers also raise with the + observed size and cap instead of returning an empty value. + +- An uncaught error in a **detached** cooperative task now stops the program (#1736). No `task_join` can ever see a detached task's failure, so its trace prints and the run stops at main's next scheduling point (the `task_yield`, or the blocking `task_join`/`task_recv`/`task_sleep`, during which it died), or in the exit drain if main never yields, with exit status 1. Before, main ran on to the end and only the exit status reported the failure. `task_detach` of a task that has already died of an uncaught error nothing joined now stops the program at that call instead of discarding the error; it used to return 1 and let the program continue. Neither stop is catchable, and both land at the same point under trace replay. Joinable tasks (main continues, a later `try`/`catch` around `task_join` recovers, never joined is exit 1) and `spawn`ed OS threads (main completes, exit 1) are unchanged; why threads differ is in docs/CONCURRENCY.md. A detached task that must survive its own errors should catch them inside the task. + +- The bitwise operators (`& | ^ << >> ~`) and the `bit_and`/`bit_or`/`bit_xor`/`bit_shl`/`bit_shr`/`bit_not` builtins now follow Lua 5.4's rule: every operand, the shift count included, must be an exact integer in [-2^63, 2^63). A fractional operand (`1.5 | 0`, `1 << 0.5`) or an out-of-range one (`1e30 | 0`, `9223372036854775808 | 0`) raises a catchable `value` error ("number has no integer representation"). Before, a fraction was silently truncated toward zero (`1.5 | 0` was `1`) and an out-of-range operand became INT64_MIN (#1739). Exact-integer operands give the same results as before, and JIT-compiled code bails to the interpreter so every tier raises the same error. + +- The numeric `improving` observer predicate is now directional, following the machine-learning loss convention that lower is better. A decreasing trajectory with contracting steps can be improving; a growing trajectory never is, even when it rises toward a plateau (#1771). + +- `rm` is no longer a builtin; `remove_file` is the one file-deletion builtin, and it raises `io` with the path and the OS reason on failure (#1884). When the file may already be missing, guard with `if file_exists of path:` before `remove_file of path`. `file_exists` follows symlinks, so that guard skips a dangling symlink. To delete one too, call `remove_file` inside `try` and handle the `io` error. `remove_file` is also bridged into the `eigen_run` meta-interpreter, where `rm` was. + +### Fixed + +- A thread calling a module-level function while another thread rebinds the same + name (a `define`, an outward `is`, or two workers `load_file`-ing one module) no + longer uses the old function after the rebind has freed it (#1171). The reader + now takes its reference inside the lock the rebind holds while it releases the + old value, the assignment count is bumped inside that lock too, and inline + caches filled before the first `spawn` can no longer read such a binding + without it. A call also keeps its callee until the new frame holds the + callee's code: a function from a `load_file`'d module whose name was rebound + while its call was being set up (by another thread, or by the call's own + argument reloading the module) used to run freed code, even single-threaded. + Which value a racing reader gets is still the program's own race. A binding in + a function's scope that closures on two threads share is not covered yet + (#1837). + +- Made `json.json_has` test key presence rather than value, so missing keys return `false` while present keys containing JSON `null` return `true`, including along dotted paths. + +- Flat list and dictionary literals no longer exhaust the parser nesting limit + by accumulating operator-chain depth across sibling elements. Deeply nested + expressions and long operator chains remain bounded by the existing limit. + +- Made `read_line` preserve line-ending bytes so pipe and redirected-file input agree and callers can distinguish a terminated final line. + +- An uncaught error raised inside an `unobserved:` block no longer leaves the observer off for everything that runs afterwards on the same state. In the REPL, every later predicate failed with "the observer is off inside an 'unobserved:' block" for the rest of the session, and an embedder reusing one state saw the same. The VM's uncaught-error halt now restores the depth it had at entry, as a `try` handler already restores its saved depth. Found by an invariant check added to the libFuzzer harness. + +- `range` now raises a `value` error when a bound or step is outside the int range. Before, `range of [0, 3e9]` silently returned an empty list. The same happened to in-range bounds whose span overflowed (`range of [-2e9, 2e9]`), which now reports the 1M-element limit error. A left shift of a negative value is now defined (two's-complement); bitwise operands outside int64 now raise (see the #1740 entry). Calls into JIT-emitted code skip clang's `-fsanitize=function` probe, which crashed sanitizer builds when emitted code began at the start of a page. Found by libFuzzer. + +- `thread_join` now re-raises an OS worker's uncaught error with its original kind and message. Catching that join observes the worker failure and allows a successful exit, matching `task_join`; an unjoined failed worker still fails the run. + +- Repaired observer documentation left incomplete when the observer configuration builtins were removed, removed their dead compiler scan and stale C comments, and added a docs-claims check for unregistered builtin call spellings. + +- Audio generators now raise a `value` error naming the builtin when their + duration exceeds the documented 30-second allocation limit, rather than + silently returning an empty list. Sample counts are range-checked before + conversion to C `int`. + +- `audio_noise` now replays from the trace tape. It drew its samples from libc `rand()`, seeded from the clock and recorded nowhere, so a run recorded with `EIGS_TRACE` and replayed with `EIGS_REPLAY` printed different samples at exit 0, and `seed_random` could not pin them. The samples now come from the same stream as `random`, so `seed_random` pins them, and each call records them as `N audio_noise=[...]` records of at most 2048 samples, because one record holds only about 3,000 samples and replay refuses a truncated record. The samples stay uniform between `-amplitude` and `amplitude`. docs/TRACE.md also corrects its statement that a truncated record falls back to the live source: replay refuses it with exit 3. + +- REPL lines and repeated embed evaluations now restore cooperative task 0 after draining workers, so `task_self`, `task_yield`, and `task_join` behave like they do in a script. + +- Keep top-level `catch`, `elif`, and `else` clauses in the current REPL input unit instead of parsing them as standalone statements. + +- Preserve unobserved cooperative-task failures from spawned worker threads so they make the process exit non-zero, just as they do on the main thread. + +- Fixed a leaked argument reference in `dispatch` calls using fresh or recycled function environments. ([#1838](https://github.com/InauguralSystems/EigenScript/issues/1838)) + +- Make test assertions set a graceful nonzero process status through the new `set_exit_code` builtin. + +- Make `read_text`, `read_bytes`, and `read_bytes_buf` read pipes, `/dev/stdin`, and FIFOs to EOF while preserving their size caps and deterministic trace replay. + +- Fixed `poisson_pmf` (and so `poisson_cdf`) returning wrong results at large parameters, where `lambda^k`, `e^-lambda` or `k!` leaves the double range: `poisson_pmf of [170, 170.0]` returned `2.04e-73` instead of `0.0306`. Results where the direct formula is valid are unchanged to the last digit. ([#1861](https://github.com/InauguralSystems/EigenScript/issues/1861)) + +- A name bound by name inside a module-level `unobserved:` block reads its + binding again, instead of `null` or a value from another scope (#1883). Such + names are a `catch` binder, a `for` binder, a defined function's name, a + comprehension binder, an `import`ed module, `loop while`'s `__loop_exit__` + and `__loop_iterations__`, and a `local` in a `for` body. The block's slot + promotion now skips every such name, even when the block also assigns it with + `is`, so its reads and writes use the same storage on the interpreter, the + JIT and forced OSR. + +- Replay is side-effect-free, as in rr (#1885). Under `EIGS_REPLAY`, module source + for `import` and `load_file` comes from the tape, and filesystem mutations + (`mkdir`, `write_text`, `write_bytes`, `remove_file`, `rename`) perform nothing + and return their recorded results. A replay no longer depends on what the + record run left on disk. The tape format is now v7. Over-cap `read_text` and + `read_bytes` tapes replay their recorded `io` error and cap message instead of + failing return-kind validation (#1890). + +- `equilibrium` no longer answers true for a one-direction tail; the #1891 flicker is documented with measured rates, not fixed. + +- Make replay stop oversized imports, strictly validate taped hashes, tape SDL ticks, keep ordering sleeps live, preserve worker exit codes, and reproduce model-load output. + +- Report embedding buffer type and bounds failures through the pending-error channel. + +- Make `f64_from_bytes` reject inputs containing fewer than eight bytes. + +- Report type mismatches from numeric, boolean, and list-length embed accessors without changing their sentinels. + +- `shared_get`, `shared_set`, `shared_incr`, `shared_has` and `shared_delete` raise `type_mismatch` for a wrong-typed argument by default, instead of answering the same value as a missing key (`null`, `false` or `0`). Under `EIGS_STRICT=0` they keep that answer (#1947). + +### Documentation + +- `docs/TRACE.md` now states the math library as a replay boundary: hosted builds use the platform libm and the freestanding build its own, so a tape that calls transcendental functions may not replay byte-identically on a different platform. ([#1853](https://github.com/InauguralSystems/EigenScript/issues/1853)) + +- The v0.47.0 release review corrected two documentation claims (#1938). `docs/CONCURRENCY.md` no longer says that a nondeterministic builtin on a `spawn`ed worker raises under `EIGS_REPLAY`, and the coverage note in `docs/TRACE.md` no longer calls the worker replay check fail-loud: each thread replays from its own tape stream (#1566). The receive family still raises under replay, and the order in which threads ran is still not on the tape. The editor hover text for `mkdir`, `remove_file` and `write_text`, and the `rename` signature comment, now say these builtins return `true` on success, not `1`. + +- Fixed builtin documentation and LSP hovers that described boolean results as numeric `0`/`1`, and added a documentation check against regressions. + ## [0.46.0] - 2026-10-11 ### Breaking changes diff --git a/VERSION b/VERSION index 301092317..421ab545d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.46.0 +0.47.0 diff --git a/changes/added/1746-observer-oracle.md b/changes/added/1746-observer-oracle.md deleted file mode 100644 index e079c6a03..000000000 --- a/changes/added/1746-observer-oracle.md +++ /dev/null @@ -1 +0,0 @@ -- `make observer-oracle` scores the observer against a corpus graded by mathematics (Hardy, NIST 6.4.4.2) and by stated conventions (numpy `isclose`, Keras `mode=min`, settling time), decided on #1754. Each predicate is scored against one question (at a NaN checkpoint, the #1758 NaN convention); the labels are derived from per-sequence properties that `certify.py` certifies offline with sympy on the values the runtime is fed. Every row runs as module-level code (`x` a name) and as a loop (`x` a slot local) under the interpreter, the default JIT and forced OSR, and every run's bytecode listing must show the path its arm grades. A jit-tier run must witness that every iteration ran natively; an osr-tier run witnesses its last iteration only (earlier ones: #1768); a run that bails on an inf, NaN or clamped value counts as interpreted. Predicate reads always run interpreted. Rows that need IEEE inf/NaN or exact int64 values (derived from their values) run where one probe finds the capability (`EXPECT=ieee,int64` makes an absent one fail). A FINDING (any reading that differs between arms) or a wrong verdict on such a row fails the run, and so, by default (`FLOOR=` skips it), does any verdict lost against the v0.46.0 tag in `tools/observer_oracle/floor.json`, re-measured on the binary `tools/observer_oracle/build_anchor.sh` builds, or reuses, in the user cache; the floor is identified by the recipe and its verdicts, not the binary's bytes (#1746, #1758, #1764). The required CI check `observer oracle (floor)` runs it on every code change, against an anchor it builds itself under `env -i` in a digest-pinned image. A gate self-test (`plants.py --selftest`, run when the oracle changes) proves that the floor reports a reversed reading for every predicate, class and label direction as lost (#1764, #1778). On the reference model, distance beats entropy as the signal (#1667). diff --git a/changes/breaking/1938-upgrading-from-0-46.md b/changes/breaking/1938-upgrading-from-0-46.md deleted file mode 100644 index 9108191b0..000000000 --- a/changes/breaking/1938-upgrading-from-0-46.md +++ /dev/null @@ -1 +0,0 @@ -- **Upgrading from 0.46.0:** four announced changes need code changes in some programs: the `rm` builtin is removed (use `remove_file`, #1884); removing a missing file raises `io` (#1668); tape format v7 records loaded module source as `load_file_source`/`load_file_source_chunk`, so a check that a tape holds only argv must allow them; and the observer predicates `improving` (#1771) and `equilibrium` (#1891) changed. The per-consumer table is in `docs/release-reviews/v0.47.0.md` (#1938). diff --git a/changes/changed/1668-file-read-errors.md b/changes/changed/1668-file-read-errors.md deleted file mode 100644 index beec6be60..000000000 --- a/changes/changed/1668-file-read-errors.md +++ /dev/null @@ -1,6 +0,0 @@ -- `read_text`, `read_bytes`, and `read_bytes_buf` now raise catchable `io` - errors containing the path and operating-system reason instead of returning - an empty failure sentinel. -- File writes, removal, rename, directory creation, and directory listing now - follow the same contract; fixed-cap text/list readers also raise with the - observed size and cap instead of returning an empty value. diff --git a/changes/changed/1736-detached-task-fail-fast.md b/changes/changed/1736-detached-task-fail-fast.md deleted file mode 100644 index b0b57a27d..000000000 --- a/changes/changed/1736-detached-task-fail-fast.md +++ /dev/null @@ -1 +0,0 @@ -- An uncaught error in a **detached** cooperative task now stops the program (#1736). No `task_join` can ever see a detached task's failure, so its trace prints and the run stops at main's next scheduling point (the `task_yield`, or the blocking `task_join`/`task_recv`/`task_sleep`, during which it died), or in the exit drain if main never yields, with exit status 1. Before, main ran on to the end and only the exit status reported the failure. `task_detach` of a task that has already died of an uncaught error nothing joined now stops the program at that call instead of discarding the error; it used to return 1 and let the program continue. Neither stop is catchable, and both land at the same point under trace replay. Joinable tasks (main continues, a later `try`/`catch` around `task_join` recovers, never joined is exit 1) and `spawn`ed OS threads (main completes, exit 1) are unchanged; why threads differ is in docs/CONCURRENCY.md. A detached task that must survive its own errors should catch them inside the task. diff --git a/changes/changed/1740-bitwise-exact-int.md b/changes/changed/1740-bitwise-exact-int.md deleted file mode 100644 index 40470ac52..000000000 --- a/changes/changed/1740-bitwise-exact-int.md +++ /dev/null @@ -1 +0,0 @@ -- The bitwise operators (`& | ^ << >> ~`) and the `bit_and`/`bit_or`/`bit_xor`/`bit_shl`/`bit_shr`/`bit_not` builtins now follow Lua 5.4's rule: every operand, the shift count included, must be an exact integer in [-2^63, 2^63). A fractional operand (`1.5 | 0`, `1 << 0.5`) or an out-of-range one (`1e30 | 0`, `9223372036854775808 | 0`) raises a catchable `value` error ("number has no integer representation"). Before, a fraction was silently truncated toward zero (`1.5 | 0` was `1`) and an out-of-range operand became INT64_MIN (#1739). Exact-integer operands give the same results as before, and JIT-compiled code bails to the interpreter so every tier raises the same error. diff --git a/changes/changed/1771-directional-improving.md b/changes/changed/1771-directional-improving.md deleted file mode 100644 index e01e5e87e..000000000 --- a/changes/changed/1771-directional-improving.md +++ /dev/null @@ -1 +0,0 @@ -- The numeric `improving` observer predicate is now directional, following the machine-learning loss convention that lower is better. A decreasing trajectory with contracting steps can be improving; a growing trajectory never is, even when it rises toward a plateau (#1771). diff --git a/changes/changed/1884-rm.md b/changes/changed/1884-rm.md deleted file mode 100644 index c15245f72..000000000 --- a/changes/changed/1884-rm.md +++ /dev/null @@ -1 +0,0 @@ -- `rm` is no longer a builtin; `remove_file` is the one file-deletion builtin, and it raises `io` with the path and the OS reason on failure (#1884). When the file may already be missing, guard with `if file_exists of path:` before `remove_file of path`. `file_exists` follows symlinks, so that guard skips a dangling symlink. To delete one too, call `remove_file` inside `try` and handle the `io` error. `remove_file` is also bridged into the `eigen_run` meta-interpreter, where `rm` was. diff --git a/changes/documentation/1853-libm-replay-boundary.md b/changes/documentation/1853-libm-replay-boundary.md deleted file mode 100644 index 5f712dca5..000000000 --- a/changes/documentation/1853-libm-replay-boundary.md +++ /dev/null @@ -1 +0,0 @@ -- `docs/TRACE.md` now states the math library as a replay boundary: hosted builds use the platform libm and the freestanding build its own, so a tape that calls transcendental functions may not replay byte-identically on a different platform. ([#1853](https://github.com/InauguralSystems/EigenScript/issues/1853)) diff --git a/changes/documentation/1938-v0470-review-docs-drift.md b/changes/documentation/1938-v0470-review-docs-drift.md deleted file mode 100644 index 535c24e46..000000000 --- a/changes/documentation/1938-v0470-review-docs-drift.md +++ /dev/null @@ -1 +0,0 @@ -- The v0.47.0 release review corrected two documentation claims (#1938). `docs/CONCURRENCY.md` no longer says that a nondeterministic builtin on a `spawn`ed worker raises under `EIGS_REPLAY`, and the coverage note in `docs/TRACE.md` no longer calls the worker replay check fail-loud: each thread replays from its own tape stream (#1566). The receive family still raises under replay, and the order in which threads ran is still not on the tape. The editor hover text for `mkdir`, `remove_file` and `write_text`, and the `rename` signature comment, now say these builtins return `true` on success, not `1`. diff --git a/changes/documentation/1945-bool-results.md b/changes/documentation/1945-bool-results.md deleted file mode 100644 index 4fb41c89c..000000000 --- a/changes/documentation/1945-bool-results.md +++ /dev/null @@ -1 +0,0 @@ -- Fixed builtin documentation and LSP hovers that described boolean results as numeric `0`/`1`, and added a documentation check against regressions. diff --git a/changes/fixed/1171-rebind-call-race.md b/changes/fixed/1171-rebind-call-race.md deleted file mode 100644 index 382b3bcb5..000000000 --- a/changes/fixed/1171-rebind-call-race.md +++ /dev/null @@ -1,13 +0,0 @@ -- A thread calling a module-level function while another thread rebinds the same - name (a `define`, an outward `is`, or two workers `load_file`-ing one module) no - longer uses the old function after the rebind has freed it (#1171). The reader - now takes its reference inside the lock the rebind holds while it releases the - old value, the assignment count is bumped inside that lock too, and inline - caches filled before the first `spawn` can no longer read such a binding - without it. A call also keeps its callee until the new frame holds the - callee's code: a function from a `load_file`'d module whose name was rebound - while its call was being set up (by another thread, or by the call's own - argument reloading the module) used to run freed code, even single-threaded. - Which value a racing reader gets is still the program's own race. A binding in - a function's scope that closures on two threads share is not covered yet - (#1837). diff --git a/changes/fixed/1652-json-has.md b/changes/fixed/1652-json-has.md deleted file mode 100644 index 81b5adbb8..000000000 --- a/changes/fixed/1652-json-has.md +++ /dev/null @@ -1 +0,0 @@ -- Made `json.json_has` test key presence rather than value, so missing keys return `false` while present keys containing JSON `null` return `true`, including along dotted paths. diff --git a/changes/fixed/1655-parser-sibling-depth.md b/changes/fixed/1655-parser-sibling-depth.md deleted file mode 100644 index b1767fc0c..000000000 --- a/changes/fixed/1655-parser-sibling-depth.md +++ /dev/null @@ -1,3 +0,0 @@ -- Flat list and dictionary literals no longer exhaust the parser nesting limit - by accumulating operator-chain depth across sibling elements. Deeply nested - expressions and long operator chains remain bounded by the existing limit. diff --git a/changes/fixed/1662-byte-exact-read-line.md b/changes/fixed/1662-byte-exact-read-line.md deleted file mode 100644 index 4809d540e..000000000 --- a/changes/fixed/1662-byte-exact-read-line.md +++ /dev/null @@ -1 +0,0 @@ -- Made `read_line` preserve line-ending bytes so pipe and redirected-file input agree and callers can distinguish a terminated final line. diff --git a/changes/fixed/1735-unobserved-uncaught-halt.md b/changes/fixed/1735-unobserved-uncaught-halt.md deleted file mode 100644 index 876f7847b..000000000 --- a/changes/fixed/1735-unobserved-uncaught-halt.md +++ /dev/null @@ -1 +0,0 @@ -- An uncaught error raised inside an `unobserved:` block no longer leaves the observer off for everything that runs afterwards on the same state. In the REPL, every later predicate failed with "the observer is off inside an 'unobserved:' block" for the rest of the session, and an embedder reusing one state saw the same. The VM's uncaught-error halt now restores the depth it had at entry, as a `try` handler already restores its saved depth. Found by an invariant check added to the libFuzzer harness. diff --git a/changes/fixed/1739-fuzz-run5-casts.md b/changes/fixed/1739-fuzz-run5-casts.md deleted file mode 100644 index b363ab5bf..000000000 --- a/changes/fixed/1739-fuzz-run5-casts.md +++ /dev/null @@ -1 +0,0 @@ -- `range` now raises a `value` error when a bound or step is outside the int range. Before, `range of [0, 3e9]` silently returned an empty list. The same happened to in-range bounds whose span overflowed (`range of [-2e9, 2e9]`), which now reports the 1M-element limit error. A left shift of a negative value is now defined (two's-complement); bitwise operands outside int64 now raise (see the #1740 entry). Calls into JIT-emitted code skip clang's `-fsanitize=function` probe, which crashed sanitizer builds when emitted code began at the start of a page. Found by libFuzzer. diff --git a/changes/fixed/1745-thread-join-error.md b/changes/fixed/1745-thread-join-error.md deleted file mode 100644 index 540799e35..000000000 --- a/changes/fixed/1745-thread-join-error.md +++ /dev/null @@ -1 +0,0 @@ -- `thread_join` now re-raises an OS worker's uncaught error with its original kind and message. Catching that join observes the worker failure and allows a successful exit, matching `task_join`; an unjoined failed worker still fails the run. diff --git a/changes/fixed/1747-observer-docs.md b/changes/fixed/1747-observer-docs.md deleted file mode 100644 index 14be90965..000000000 --- a/changes/fixed/1747-observer-docs.md +++ /dev/null @@ -1 +0,0 @@ -- Repaired observer documentation left incomplete when the observer configuration builtins were removed, removed their dead compiler scan and stale C comments, and added a docs-claims check for unregistered builtin call spellings. diff --git a/changes/fixed/1767-audio-generator-duration.md b/changes/fixed/1767-audio-generator-duration.md deleted file mode 100644 index 463b00b28..000000000 --- a/changes/fixed/1767-audio-generator-duration.md +++ /dev/null @@ -1,4 +0,0 @@ -- Audio generators now raise a `value` error naming the builtin when their - duration exceeds the documented 30-second allocation limit, rather than - silently returning an empty list. Sample counts are range-checked before - conversion to C `int`. diff --git a/changes/fixed/1803-audio-noise-tape.md b/changes/fixed/1803-audio-noise-tape.md deleted file mode 100644 index 629deaae3..000000000 --- a/changes/fixed/1803-audio-noise-tape.md +++ /dev/null @@ -1 +0,0 @@ -- `audio_noise` now replays from the trace tape. It drew its samples from libc `rand()`, seeded from the clock and recorded nowhere, so a run recorded with `EIGS_TRACE` and replayed with `EIGS_REPLAY` printed different samples at exit 0, and `seed_random` could not pin them. The samples now come from the same stream as `random`, so `seed_random` pins them, and each call records them as `N audio_noise=[...]` records of at most 2048 samples, because one record holds only about 3,000 samples and replay refuses a truncated record. The samples stay uniform between `-amplitude` and `amplitude`. docs/TRACE.md also corrects its statement that a truncated record falls back to the live source: replay refuses it with exit 3. diff --git a/changes/fixed/1807-repl-task-current.md b/changes/fixed/1807-repl-task-current.md deleted file mode 100644 index 14182c8c7..000000000 --- a/changes/fixed/1807-repl-task-current.md +++ /dev/null @@ -1 +0,0 @@ -- REPL lines and repeated embed evaluations now restore cooperative task 0 after draining workers, so `task_self`, `task_yield`, and `task_join` behave like they do in a script. diff --git a/changes/fixed/1809-repl-dedented-clauses.md b/changes/fixed/1809-repl-dedented-clauses.md deleted file mode 100644 index d1ae5a2bd..000000000 --- a/changes/fixed/1809-repl-dedented-clauses.md +++ /dev/null @@ -1 +0,0 @@ -- Keep top-level `catch`, `elif`, and `else` clauses in the current REPL input unit instead of parsing them as standalone statements. diff --git a/changes/fixed/1810-worker-task-exit-status.md b/changes/fixed/1810-worker-task-exit-status.md deleted file mode 100644 index 5d73e8b72..000000000 --- a/changes/fixed/1810-worker-task-exit-status.md +++ /dev/null @@ -1 +0,0 @@ -- Preserve unobserved cooperative-task failures from spawned worker threads so they make the process exit non-zero, just as they do on the main thread. diff --git a/changes/fixed/1838-dispatch-argument-ownership.md b/changes/fixed/1838-dispatch-argument-ownership.md deleted file mode 100644 index 312adfe4c..000000000 --- a/changes/fixed/1838-dispatch-argument-ownership.md +++ /dev/null @@ -1 +0,0 @@ -- Fixed a leaked argument reference in `dispatch` calls using fresh or recycled function environments. ([#1838](https://github.com/InauguralSystems/EigenScript/issues/1838)) diff --git a/changes/fixed/1839-test-exit-code.md b/changes/fixed/1839-test-exit-code.md deleted file mode 100644 index d7976dd20..000000000 --- a/changes/fixed/1839-test-exit-code.md +++ /dev/null @@ -1 +0,0 @@ -- Make test assertions set a graceful nonzero process status through the new `set_exit_code` builtin. diff --git a/changes/fixed/1845-stream-readers.md b/changes/fixed/1845-stream-readers.md deleted file mode 100644 index 89a5dcb1d..000000000 --- a/changes/fixed/1845-stream-readers.md +++ /dev/null @@ -1 +0,0 @@ -- Make `read_text`, `read_bytes`, and `read_bytes_buf` read pipes, `/dev/stdin`, and FIFOs to EOF while preserving their size caps and deterministic trace replay. diff --git a/changes/fixed/1861-poisson-pmf-large-parameters.md b/changes/fixed/1861-poisson-pmf-large-parameters.md deleted file mode 100644 index ac3df1f04..000000000 --- a/changes/fixed/1861-poisson-pmf-large-parameters.md +++ /dev/null @@ -1 +0,0 @@ -- Fixed `poisson_pmf` (and so `poisson_cdf`) returning wrong results at large parameters, where `lambda^k`, `e^-lambda` or `k!` leaves the double range: `poisson_pmf of [170, 170.0]` returned `2.04e-73` instead of `0.0306`. Results where the direct formula is valid are unchanged to the last digit. ([#1861](https://github.com/InauguralSystems/EigenScript/issues/1861)) diff --git a/changes/fixed/1883-unobserved-catch-binding.md b/changes/fixed/1883-unobserved-catch-binding.md deleted file mode 100644 index b0b706d80..000000000 --- a/changes/fixed/1883-unobserved-catch-binding.md +++ /dev/null @@ -1,8 +0,0 @@ -- A name bound by name inside a module-level `unobserved:` block reads its - binding again, instead of `null` or a value from another scope (#1883). Such - names are a `catch` binder, a `for` binder, a defined function's name, a - comprehension binder, an `import`ed module, `loop while`'s `__loop_exit__` - and `__loop_iterations__`, and a `local` in a `for` body. The block's slot - promotion now skips every such name, even when the block also assigns it with - `is`, so its reads and writes use the same storage on the interpreter, the - JIT and forced OSR. diff --git a/changes/fixed/1885-side-effect-free-replay.md b/changes/fixed/1885-side-effect-free-replay.md deleted file mode 100644 index 844bf9ed4..000000000 --- a/changes/fixed/1885-side-effect-free-replay.md +++ /dev/null @@ -1,7 +0,0 @@ -- Replay is side-effect-free, as in rr (#1885). Under `EIGS_REPLAY`, module source - for `import` and `load_file` comes from the tape, and filesystem mutations - (`mkdir`, `write_text`, `write_bytes`, `remove_file`, `rename`) perform nothing - and return their recorded results. A replay no longer depends on what the - record run left on disk. The tape format is now v7. Over-cap `read_text` and - `read_bytes` tapes replay their recorded `io` error and cap message instead of - failing return-kind validation (#1890). diff --git a/changes/fixed/1891-modulated-raw-steps.md b/changes/fixed/1891-modulated-raw-steps.md deleted file mode 100644 index b4e4fc545..000000000 --- a/changes/fixed/1891-modulated-raw-steps.md +++ /dev/null @@ -1 +0,0 @@ -- `equilibrium` no longer answers true for a one-direction tail; the #1891 flicker is documented with measured rates, not fixed. diff --git a/changes/fixed/1914-replay-followups.md b/changes/fixed/1914-replay-followups.md deleted file mode 100644 index da5cf3c5b..000000000 --- a/changes/fixed/1914-replay-followups.md +++ /dev/null @@ -1 +0,0 @@ -- Make replay stop oversized imports, strictly validate taped hashes, tape SDL ticks, keep ordering sleeps live, preserve worker exit codes, and reproduce model-load output. diff --git a/changes/fixed/1925-embed-buffer-oob-error.md b/changes/fixed/1925-embed-buffer-oob-error.md deleted file mode 100644 index c4cc78120..000000000 --- a/changes/fixed/1925-embed-buffer-oob-error.md +++ /dev/null @@ -1 +0,0 @@ -- Report embedding buffer type and bounds failures through the pending-error channel. diff --git a/changes/fixed/1926-f64-from-bytes-short-input.md b/changes/fixed/1926-f64-from-bytes-short-input.md deleted file mode 100644 index 841fef5f2..000000000 --- a/changes/fixed/1926-f64-from-bytes-short-input.md +++ /dev/null @@ -1 +0,0 @@ -- Make `f64_from_bytes` reject inputs containing fewer than eight bytes. diff --git a/changes/fixed/1932-embed-accessor-type-errors.md b/changes/fixed/1932-embed-accessor-type-errors.md deleted file mode 100644 index e03b42079..000000000 --- a/changes/fixed/1932-embed-accessor-type-errors.md +++ /dev/null @@ -1 +0,0 @@ -- Report type mismatches from numeric, boolean, and list-length embed accessors without changing their sentinels. diff --git a/changes/fixed/1947-http-shared-key-type.md b/changes/fixed/1947-http-shared-key-type.md deleted file mode 100644 index 0c0a261d2..000000000 --- a/changes/fixed/1947-http-shared-key-type.md +++ /dev/null @@ -1 +0,0 @@ -- `shared_get`, `shared_set`, `shared_incr`, `shared_has` and `shared_delete` raise `type_mismatch` for a wrong-typed argument by default, instead of answering the same value as a missing key (`null`, `false` or `0`). Under `EIGS_STRICT=0` they keep that answer (#1947). diff --git a/changes/internal/1690-remove-dead-json-raw.md b/changes/internal/1690-remove-dead-json-raw.md deleted file mode 100644 index 672d00dba..000000000 --- a/changes/internal/1690-remove-dead-json-raw.md +++ /dev/null @@ -1 +0,0 @@ -- Remove the unconstructible VAL_JSON_RAW value kind and its dead handling branches and comments after json_raw was removed in #1677. Preserve all surviving ValType tag numbers and exhaustive switch checking; no guest-language behavior changes. diff --git a/changes/internal/1694-exec-capture-sigpipe-contract.md b/changes/internal/1694-exec-capture-sigpipe-contract.md deleted file mode 100644 index 9bd0c8796..000000000 --- a/changes/internal/1694-exec-capture-sigpipe-contract.md +++ /dev/null @@ -1 +0,0 @@ -- Pin exec_capture preserving the host SIGPIPE handler and inherited ignored disposition, including the closed-stdout print path. diff --git a/changes/internal/1775-amalgamation-debug-warnings.md b/changes/internal/1775-amalgamation-debug-warnings.md deleted file mode 100644 index 35a06e135..000000000 --- a/changes/internal/1775-amalgamation-debug-warnings.md +++ /dev/null @@ -1 +0,0 @@ -- Make amalgamation return paths and local initialization explicit for warning-free debug and lightly optimized builds; runtime behavior is unchanged. diff --git a/changes/internal/1781-stale-observer-declarations.md b/changes/internal/1781-stale-observer-declarations.md deleted file mode 100644 index 8e2e35ba6..000000000 --- a/changes/internal/1781-stale-observer-declarations.md +++ /dev/null @@ -1 +0,0 @@ -- Remove unimplemented observer declarations and stale references; no changelog entry is needed because no callable API or runtime behavior changes. diff --git a/changes/internal/1859-gcc14-set-at-warning.md b/changes/internal/1859-gcc14-set-at-warning.md deleted file mode 100644 index 7aab54bd3..000000000 --- a/changes/internal/1859-gcc14-set-at-warning.md +++ /dev/null @@ -1 +0,0 @@ -- No user-visible change: `set_at` reads its buffer argument by reference instead of through a stack view, so gcc 14 no longer warns `-Wreturn-local-addr` when it compiles the amalgamation (#1859). The `-O0`/`-O1` warnings are #1775, fixed by contributor PR #1799. diff --git a/changes/internal/1872-clang-amalgamation-warnings.md b/changes/internal/1872-clang-amalgamation-warnings.md deleted file mode 100644 index 4c0b0eae1..000000000 --- a/changes/internal/1872-clang-amalgamation-warnings.md +++ /dev/null @@ -1 +0,0 @@ -- Clang warning cleanup, explicit VM index-write initialization for GCC 13, and amalgamation warning checks at -O0/-O1; opcode names, optional helper APIs and borrowed-view behavior are unchanged, so no user-facing entry is needed. diff --git a/changes/internal/1916-gfx-timeout-control-budgets.md b/changes/internal/1916-gfx-timeout-control-budgets.md deleted file mode 100644 index b2b48b978..000000000 --- a/changes/internal/1916-gfx-timeout-control-budgets.md +++ /dev/null @@ -1 +0,0 @@ -- Give completion-based gfx timeout controls a jitter-safe budget while keeping deliberate timeout controls fast. diff --git a/changes/internal/1916-gfx-timeout-timing-line.md b/changes/internal/1916-gfx-timeout-timing-line.md deleted file mode 100644 index 308d2821e..000000000 --- a/changes/internal/1916-gfx-timeout-timing-line.md +++ /dev/null @@ -1 +0,0 @@ -- The ext_gfx sanitizer section prints the timeout controls' completion-wall and process-start line on every pass, so each CI host records the timing its budget is sized from (#1916). diff --git a/changes/internal/1923-valgrind-install-cache.md b/changes/internal/1923-valgrind-install-cache.md deleted file mode 100644 index 664a3ce8e..000000000 --- a/changes/internal/1923-valgrind-install-cache.md +++ /dev/null @@ -1 +0,0 @@ -- Cache Valgrind packages in CI so the memory and benchmark gates do not depend on a live apt mirror. diff --git a/changes/internal/1935-pr-embed-smoke.md b/changes/internal/1935-pr-embed-smoke.md deleted file mode 100644 index adf519098..000000000 --- a/changes/internal/1935-pr-embed-smoke.md +++ /dev/null @@ -1 +0,0 @@ -- Run the release embedding smoke test on code-changing pull requests before they enter the merge queue. diff --git a/changes/internal/1938-release-legibility-review.md b/changes/internal/1938-release-legibility-review.md deleted file mode 100644 index 0167e99d3..000000000 --- a/changes/internal/1938-release-legibility-review.md +++ /dev/null @@ -1 +0,0 @@ -- Every release now records a documentation and configuration review (`docs/release-reviews/vX.Y.Z.md`), and the Release workflow refuses to tag a version without it. diff --git a/changes/internal/1938-remove-uncalled-resolve-error.md b/changes/internal/1938-remove-uncalled-resolve-error.md deleted file mode 100644 index b7b6b05f7..000000000 --- a/changes/internal/1938-remove-uncalled-resolve-error.md +++ /dev/null @@ -1 +0,0 @@ -- No user-visible change: `eigs_file_resolve_error` is removed. It had no caller once #1901 moved `load_file` and `import` to `eigs_file_resolve_message`, so that the message can be taped (#1938). diff --git a/changes/internal/1940-per-tree-build-lock.md b/changes/internal/1940-per-tree-build-lock.md deleted file mode 100644 index 1025f12b7..000000000 --- a/changes/internal/1940-per-tree-build-lock.md +++ /dev/null @@ -1 +0,0 @@ -- Serialize per-tree builds and make the stop gate skip locked trees instead of racing shared outputs. diff --git a/changes/internal/1942-share-nightly-valgrind-install.md b/changes/internal/1942-share-nightly-valgrind-install.md deleted file mode 100644 index d93ecda6b..000000000 --- a/changes/internal/1942-share-nightly-valgrind-install.md +++ /dev/null @@ -1 +0,0 @@ -- Reuse the cached, bounded Valgrind installer in the nightly workflow and remove its unused test-only apt options. diff --git a/changes/internal/1943-deduplicate-replay-and-tape-rules.md b/changes/internal/1943-deduplicate-replay-and-tape-rules.md deleted file mode 100644 index e7e101707..000000000 --- a/changes/internal/1943-deduplicate-replay-and-tape-rules.md +++ /dev/null @@ -1 +0,0 @@ -- Deduplicate replay boundary refusals and derive filesystem error taping from the canonical tape-kind table. diff --git a/changes/internal/1944-shared-doc-call-claims.md b/changes/internal/1944-shared-doc-call-claims.md deleted file mode 100644 index 737d62e1f..000000000 --- a/changes/internal/1944-shared-doc-call-claims.md +++ /dev/null @@ -1 +0,0 @@ -- Share one matcher and API vocabulary across all documentation call-claim checks, and remove the unused direct-registration count (#1944). diff --git a/changes/internal/1948-stale-references.md b/changes/internal/1948-stale-references.md deleted file mode 100644 index 2e9b157d8..000000000 --- a/changes/internal/1948-stale-references.md +++ /dev/null @@ -1 +0,0 @@ -- Refresh stale issue states and paths in comments, and record why the suite's runner-guard calibrations remain inline.