Changes since alpha.1
Current-main behavior, migration notes and limits after the published preview.
These docs track main, including Unreleased changes.
The published npm latest is 0.1.0-alpha.1; use a source build
for the changes below until a newer release publishes. This page does not declare
M4 complete or stabilize experimental native execution.
Sources, diagnostics and portability
- Sources now end in
.sak, with no old-extension fallback. Rename old files withgit mv main.sakura main.sak.sakura.toml, thesakuralanguage id andsakura:///std/…URIs stay unchanged. - CRLF and LF have the same meaning, including newlines in strings.
sakura fmtwrites LF;fmt --checkidentifies CRLF as a formatting difference. A snapshot differing only in line endings is reported as a line-ending mismatch. Scaffolding writes.gitattributeswith*.sak text eol=lfand*.snap -text. - JSON file URIs follow RFC 8089, including
file:///C:/dir/main.sak. Terminal diagnostics use OS paths, without URI escapes. MCP path filters accept equivalent file URI spellings. On Windows, Node lookup honorsPATHEXTand solver lookup uses.exe. These fixes are not a claim of a supported Windows release. V1002onType.membercan suggest a unique prefix/extension match when there is no near spelling:List.lenght→len,List.fil→filter. These fixes aresuggested, never automatically safe;List.sizeno longer suggestsslice.V2002names a declared callee and its module, with expected and actual argument counts. A function-value call retains the type form.V3001can propose the effect's unique deterministic std handler; that edit remainsincomplete.- Syntax-error suppression follows place: diagnostics whose spans point into
the broken body are suppressed, as is its cascading
V3001. An error in another module used from that body remains visible. Rechecks invalidate refinement dependencies through contracts and no longer duplicate reused tests' diagnostics. V4004limits amatch,catchorletpattern decision tree to 1,048,576 nodes, not a fixed arm count. Or-pattern combinations and copied wildcard rows can expand the tree. It is diagnosed during lowering (build,run,test), notcheck. Thousands of flat literal or guarded rows can compile and run; split combinatorial matches into one column at a time. SeeV4004.
Analysis cache and check latency
check, build, run, test, LSP and MCP reuse std analysis from a disk cache,
one file per compiler build at <cache>/sakuralang/std. The base is
SAKURA_CACHE_DIR, otherwise XDG_CACHE_HOME or ~/.cache on Unix and
LOCALAPPDATA on Windows. SAKURA_NO_CACHE=1 disables it. Missing, damaged or
foreign entries are recomputed; files are disposable and have no format guarantee.
This is separate from the authenticated proof cache.
Concurrent test jobs should set distinct SAKURA_CACHE_DIR directories.
The recorded release-build measurements on one quiet macOS host fell from about
22 to 7 ms for sakura new cli and from 54 to 39 ms for a 10k-line check. These are
observations, not platform guarantees. Long-lived servers also reuse std in memory.
bench/bench compile --json compile.json reproduces the compile-latency workloads;
its cache lives in bench/target/cache unless overridden.
Server limits and failures
Serve.host() bounds request bodies to 1 MiB. It rejects oversized bodies with
413, closes the connection and never calls the handler. The following additional
cases are distinct:
| Condition | HTTP response | Diagnostic and lifecycle |
|---|---|---|
| Reply status or headers cannot be sent | 500 | D091; server keeps running |
WASM request exceeds SAKURA_MAX_COPY_BYTES | 413, connection closed | D091 on stderr; handler not run, server keeps running |
| WASM handler response exceeds that budget | 500 | D091 on stderr; server keeps running |
| WASM heap cannot admit a request | 503, retry-after: 1 | D096 on stderr; server keeps running |
| WASM runtime trap during a request | 500 | One D090 naming function and PC; server stops and program exits 70 |
| Request still waiting when program ends | 500 | One D090 “server stopped”, unless a defect already ended the program |
| Request arriving on an open connection after server stops, either backend | 503, connection closed | Handler never runs |
WASM tests resume after host faults or traps on a fresh instance. Invalid host
operation indices or result shapes are D090; exhausted request tables are D091
for Clock.sleep and serve_listen. Defect records now carry JS-compatible messages
and source spans from sakura.debug (omitted by --strip).
HTTP, cassettes and filesystem security
SAKURA_MAX_COPY_BYTES must be decimal digits representing 1 through 2^53−1.
Empty, zero, signed, fractional, exponential, hexadecimal or spaced values cause
D091 at first use; unset it for the 256 MiB default. JS Http.host().send now
bounds the response body too. An oversized HTTP response is HttpError with
“response too large”, not a runtime defect; use streaming for larger responses.
A connection lost while reading a body is also HttpError on JS and WASM.
test --record stores at most 16 MiB of a sent or streamed response; exceeding it
fails with HttpError without appending the exchange. Malformed exchanges fail
when the cassette opens. Recording requires JS; WASM can replay the cassette and
run test --contracts. Tests without --record have empty host permissions;
Test.fixtures() retains its own grants. Secret HTTP headers work on WASM and
remain redacted in cassettes. Secret.map now requires an explicit trust reason,
and sakura audit lists it beside Secret.expose.
Writes through dangling symlinks inside an fs.write grant are refused with
“escapes the directory”, even when the link points back inside the grant. This
covers Fs.write, write/append File, cassette recording and Sql.sqlite on JS
and WASM. Write to the target path instead of the dangling link.
Verification and performance
sakura verify reuses authenticated verdicts, including
unknown(resource_limit) at the same budget, and replays eligible i64
counterexamples. JS and WASM builds remove eligible proved checks; total predicates
go with them, while predicates calling functions still execute. requires, entry
checks and checked arithmetic stay in this proof-removal pass. Proof key ownership,
directory permissions and location are checked; builds never create the key.
Direct WASM local-handler/callback calls, fused collection access, tag comparisons, tail-call loops and large-match lowering reduce work while preserving semantics. Core output and snapshot hashes are now independent of earlier analyses in a process; std-first file ordering can change dump IDs and hashes. Finished WASM root tasks are freed between benchmark samples.
For dense integer IDs, prefer List to Map, as the DeltaBlue benchmark now does.
Both return updated values: assign the result back. Use Map for sparse keys.
The benchmark guide
documents bench/bench envelope wasm.json native.json --json envelope.json.
Inputs must share commit and host; the native file must use the matched lane.
Exit 0 means a report was produced, not that every ceiling passed. Loaded-host and
CI results are advisory. The native comparison ports are Rust/Go/OCaml/Koka,
not a stable Sakura native backend.
Distribution and editor tooling
See Install for the published platforms and next-release additions:
Linux ARM64 (glibc) archives and npm package, coming in v0.1.0, and Windows x64 MSVC
ZIP, npm and install.ps1 packaging, coming in v0.2.0. Neither is in alpha.1.
New macOS tag releases require Developer ID signing (team P62B65A837) and Apple
notarization before archives and packages are assembled; this does not retroactively
sign alpha.1. Bare Mach-O executables cannot carry a stapled ticket. The installer
checks checksums and, when gh is available, requires successful attestation
verification; without it, it reports “integrity verified, not attested”. Custom
prefixes must be absolute.
The tree-sitter grammar is available in the repository. The generated skill, manifest and ZIP normalize Windows separators and are byte-identical across OSes. The skill entry point retains a 7,000-byte source working target and a tested 7,500-byte limit after release metadata is filled.