Soma 2.6.0 — 2026-09-19
-
soma.lock records a sha256 of each package's files: a package modified after install is refused at import, and soma install restores it.
-
Check warns when an imported cell defines request or ws (it would own HTTP routing / the WebSocket port).
-
self_call counts only ports this process listens on; a failed guard's source is not sent to clients; 204 / 304 carry no Content-Type; a quote inside {…} in a call argument gets the escaping hint.
-
Performance: a lambda's captured lists and maps are no longer copied per element — |> map / filter / … over a captured list is linear (was quadratic).
-
[native]: an Int / stays exact after the BigInt re-run (it truncated the docs' midpoint example); a handler returning its String parameter compiles; an Int overflow inside a Float/Bool expression is kind range.
-
sort_by puts NaN last; an unclosed CSV quote is an error; quantile refuses q outside [0, 1]; blank CSV cells are missing values for sum_by / avg_by; operator chains count toward the nesting limit.
-
"s" |> map(f) and "s".map(f) raise a type error; kinds rate_limited / too_many_requests answer 429.
-
WebSocket: a returned response(…) sends its body; error bodies hide private handler names; binary frames are answered with an error.
-
Clearer errors for reserved words used as JSON fields (d["cell"]) and for guard locals of a handler that may take a guarded edge.
-
Soundness: "C".delegate(…) / "C" |> delegate(…) are seen by the termination and size proofs; a let hiding a slot no longer lends the slot's bound; the latency bound counts retries (think timeout now covers them), tool rounds, sleep, and is advisory with approve / file I/O; an interpolated transition target is treated as computed.
-
[native]: an exact Int / Int with operands past 2^53 is exact; stdin read before a BigInt re-run is replayed.
-
New ipow (exact Int power) and from_csv(text); read_csv takes delimiter and refuses unknown options; map/filter/… on a non-list raise a type error; format("%.2f", Int) is exact; to_float past the Float range raises range; pow of a non-number raises.
-
In an invariant, slot.get(key) reads the stored value on Map- and record-valued slots too: write-once invariants on Map<String, Map> / List<Map> slots were not enforced.
-
approve() shows control characters as escapes (a model could redraw the prompt); every reply shape is measured against max_tokens and the budget, a reply with no text raises kind llm; a set_budget reached from a tool call can only lower the caller's budget; ..;/ is refused by capability path scopes.
-
A List delete is checked by size invariants only (as verify says); require … else budget answers 400.
-
A JSON request body or bus event with more than 1 000 000 values is refused before parsing (a 15 MB line became 2.4 GB in memory).
-
Events sent after a linked peer disconnected are logged NOT delivered; soma run warns when an emit meant for [peers] goes nowhere.
-
Check warns on m.size ?? default (.size is the entry count, never ()); a negative [native] buffer index is reported as written.
-
Every path-taking builtin (load, include, load_template, read_files, par_read_files, word_count) refuses a .. segment: load("templates/" + name) could serve any file.
-
The bus port opens only for [peers], [bus] accept, scale or --join: an in-process emit no longer exposes the program's listeners.
-
Kinds unauthorized / unauthenticated answer 401; error bodies no longer name private handlers; the loopback Host check parses the whole authority and refuses duplicate Host headers.
-
SOMA_LLM_MOCK=fixed: over max_tokens raises kind llm like a scripted mock; guard locals bound after a transition to another state are accepted.
-
The file write guard is case-insensitive; self_call recognises every spelling of this machine; Origin: null / file:// writes are refused on loopback servers.
-
LLM replies are measured as well as counted: an under-reported reply cannot pass max_tokens or the proven cost bound.
-
File builtins refuse .. segments and writes over the program, its configuration or storage; a loopback server refuses foreign Host headers and cross-origin writes; an HTTP call to the server itself answers self_call; tool capabilities match query spaces encoded.
-
get_status & co. from a machine-less cell with several machines, and variant literals with wrong fields, are check errors; the secret recipe fails closed; security notes in the serving docs.
-
pow_mod work is bounded (bits(exp) × bits(m) ≤ 2^30); to_int / parse_int refuse text past the 2^24-bit Int cap.
-
A bus event that reaches no peer is logged as NOT delivered; the docs give an outbox + acknowledgement pattern for transfers between processes.
-
An Int holds at most 2^24 bits: products, shl and product() past it raise kind range before they are built (interpreter and native); matmul is capped at 10^9 multiply-adds.
-
substring and range refuse wrongly typed arguments (kind type).
-
A huge declared Content-Length no longer aborts soma serve (tiny_http vendored with a chunked drain; bodies past 256 MB are refused 413).
-
A scripted mock think reply longer than max_tokens raises kind llm.
-
Bus peers have bounded send queues (a peer that stops reading is disconnected); WebSocket clients are also dropped past 64 MB queued; the WebSocket Origin check refuses userinfo and control characters.
-
A split string as the last statement of a loop body is a check error; disjunctive invariants over the written value are proven.
-
Duplicate or list-valued Content-Length is refused and the connection's pipelined bytes never run; request-log lines escape control characters.
-
Unary operator chains count toward the nesting limit; a List slot's invariant key is the Int index; html() with header pairs passes the arity check; guard variables bound in a loop body are recognised.
-
emit arity mismatches are check errors; a computed Float is refused by an Int parameter; CSV rows of empty cells survive a round trip and duplicate CSV headers are refused.
-
Parameter types are checked all the way down (HTTP, bus, tools, calls); a Float past 2^53 is not coerced into an Int parameter; [native] handlers and mocks are held to the face's return type.
-
from_json refuses undeclared _types; misspelled builtin types and extra builtin arguments are check errors; () is refused where a nested scalar is declared; write_csv keeps rows holding an empty String.
-
The equal-clause proof tolerates callees that cannot write the slot; contextual keywords work as statement variables.
-
A handler parameter may not take a slot's name; face parameter types must match the handler's.
-
verify and the guard rule see every / after ticks of machine-less cells; instance ids are Strings or Ints (() refused); a renamed machine is reported under soma run too.
-
soma run treats any non-data token as a handler name when several exist; NaN / lambdas in responses are valid JSON.
-
[native] bnot is exact past 2^63; native loop_bound errors keep their kind; soma run … request decodes the path like serve.
-
Guards of transitions taken from machine-less cells are checked; --strict fails when [verify] cells names no cell of the file; for over any finite value terminates; an emit in an imported file opens the bus.
-
The equal-clause proof applies only to pure clauses (locals, arithmetic, ??, .get of the written slot) with a plain key — other slots, nondeterministic or external reads between the require and the write made it prove refused writes.
-
Invariant slot references are counted deep (interpolation, lambdas, match arms) by the checker and the runtime; verify hints never name size / key / value; undefined functions in properties are check errors.
-
mock Cell.handler stubs that cell's handler only; mocks naming nothing, test helpers shadowing program handlers or builtins, and test cells with no assertion are errors; mocks reach [native] sibling calls.
-
--record logs calls that raised; describe / the dashboard keep except on * edges; soma fix exits 1 when errors remain.
-
A require that is exactly an invariant clause over the written value proves it (monotone versions); value / key / size outside an invariant are check errors; slots in nested lambdas are not function values.
-
soma serve refuses to start on a damaged database (quick_check); a file that is not a database is a clean error, not a panic.
-
A materialized range() is capped at 10M elements; dotfiles under static/ are not served; Content-Length + Transfer-Encoding is a 400.
-
Quant builtins enforce max_obs / max_assets and a confidence alpha in (0, 1); no false "share the path" warning for emit listeners.
-
The invariant prover is exact for Ints past 2^53 (intervals widen outward instead of rounding), counts think() tools and computed delegates among a handler's callees, and does not prove a bare slot read that may be ().
-
http_get in a loop, lambda or tool no longer makes a token bound advisory (only a latency bound); a saturated cost peak is advisory.
-
[native] i64::MIN / -1 raises instead of returning a rounded Float; guarded transitions in lambdas see the handler's locals; refinement paths keep their parentheses.
-
Statements inside block lambdas, try { }, if-expressions and match arms (slot[k] = v, emit) are seen by GET→405, the listener set, the termination graph, the size prover and guard / invariant purity.
-
return inside a block lambda is a check error; a bare return returns (); soma run … request GET "/a?x=1" splits the query; every 90m names the duration units.
-
x |> h with a bare handler name is a call for every analysis (termination, cost, route ownership, GET→405, model-driven recursion).
-
subscribe() dispatches only events the program emits or [bus] accept lists; invariants and guards may not read files, print or read stdin.
-
.field on a String or a List raises kind type; serve lists only real endpoints; [native] literal arithmetic that overflows i64 promotes to BigInt as interpreted code does.
-
Capability-scoped tools cannot load files (load, include, par_read_files, …) or link(); invariants are pure conditions (no handler call or effect builtin, however hidden); a tool calling back its think() handler is a termination ⚠; link() makes a handler POST-only; load() substitutes in one pass; a reply over its max_tokens raises.
-
Errors in imported files are reported in that file.
-
?? short-circuits; with() stores BigInt values; strict Float bounds after a require are proven; tools_allowed must name tools.
-
Interpolation segments are analysed exactly where the runtime finds them: "{ { expr } }" ran expr unseen by route ownership, termination, cost, GET→405, guard and invariant checks.
-
A returned String is sent raw only when it is valid JSON text; JSON answers carry nosniff. [native] string literals unescape {{/}}. Face return types are checked element-wise.
-
An interpolation segment holding a block ("{if c { 1 } else { 2 }}") ends at its matching brace; .size on a record without that field is (); from_json checks a declared variant's shape (a missing or mistyped field raises kind type).
-
A stack overflow is not caught by try; lambdas handing function values to map/filter are a termination ⚠; a computed delegate in request owns the cell's handlers; face tools are not HTTP endpoints.
-
Storage escapes map keys starting with __ (no refusal, no forgery); () is false in every condition; invariants must be Bool.
-
Floats print shortest digits; format("%e"); 5 redirect hops; f(a)(b) refused; unknown handler names in soma run are errors.
-
Storage refuses map keys and slot keys starting with __ (reserved by the encoding: a client body could come back as a forged variant, and such keys escaped len and size invariants).
-
A block lambda's last statement runs when it is not an expression (an emit there was dropped); conditions and predicates take Bools; route ownership follows calls through other cells; run --fresh refuses to wipe a directory a soma serve is using; verify names machines per cell.
-
A lambda call counts toward the recursion guard (self-application aborted the process); calling a function value is a termination ⚠.
-
Cost sees think() in index/field assignments; the guard rule and route ownership see UFCS, interpolation, require and emit chains.
-
A bare slot name never reaches another cell's storage (it bypassed the owner's invariant); writes to slots with non-size invariants no longer count the slot (bulk loads were quadratic).
-
mock think token accounting is capped at max_tokens.