docs(context): bookkeeping for ADR 009 steps 4-7, zset rollback, threads, edges and the scheduler

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Claude (bookkeeping2)
2026-10-10 22:24:53 -07:00
committed by Edward Langley
parent d63b2c1956
commit 482f7178d1
4 changed files with 58 additions and 8 deletions
+13 -2
View File
@@ -10,9 +10,9 @@ crate(improvise_ws_server,'crates/improvise-ws-server','the socket host: tokio +
crate(improvise_wasm_client,'crates/improvise-wasm-client','the browser client: the fold, the key classifier, and the render model the DOM paints. Non-dev deps are improvise-protocol + serde + wasm-bindgen and nothing else.').
crate(improvise_worker_server,'crates/improvise-worker-server','the other host: the same App, Sessions and Host as the socket server, behind self.onmessage/self.postMessage with OPFS underneath. worker.rs and vfs.rs are ordinary Rust and hold every decision and every test; bindings.rs is the wasm32 shim, run by harness/tests/shell.spec.js under Chromium and by no Rust test.').
crate(numtower,'crates/numtower','exact decimal arithmetic tower (ADR 005): Num, canonical text; no workspace deps. Used by improvise-protocol for the wire form.').
crate(zset,'crates/zset','std-only Z-sets (checked i64 weights) plus Circuit, operators, Trace and Rebuild (ADR 009 clause 1); no dependencies.').
crate(zset_ffi,'crates/zset-ffi','C ABI over zset (cdylib, staticlib, rlib; include/zset_ffi.h) for CFFI. native_only: not in nix/ci.nix wasmCrates.').
crate(improvise_incremental,'crates/improvise-incremental','the Derived trait, Reading, Eager, differential_in/drawn_probes and cell_delta/DeltaValue; plugs zset in behind a trait (ADR 009).').
crate(zset,'crates/zset','std-only Z-sets (checked i64 weights) plus Circuit (Send, not Sync; transactions), operators, Trace, Rebuild and edge.rs (stamped delta edges between circuits); no dependencies.').
crate(improvise_incremental,'crates/improvise-incremental','the Derived trait, Reading, Eager, Incremental (groups, formulas by stem, ExactSum), Pushdown, cell_delta/DeltaValue, and sched.rs/staged.rs (Executor of Units, native-only Pool); plugs zset in behind a trait (ADR 009).').
layer(model,improvise_core).
layer(view,improvise_core).
layer(formula,improvise_formula).
@@ -592,6 +592,15 @@ decision('improvise-felo.4',resumable_deadline_predicate,'The resumable step tak
decision('improvise-felo.4',eager_occupancy,'Eager::occupancy counts the visible stored members of a collapsed group, and formula-target keys are not asked.').
decision('improvise-z2vr',delivery_axis_refetch,'A delivery axis change makes the correction a window refetch until ADR 008 supplies the render model (context/code/delivery.md section 3).').
decision('improvise-felo.4',dirty_flag_is_delta_plus,'The document dirty flag is each CellData effect own cell delta (drained after every such effect, so ordering with Save holds) plus reorders, formulas and config; writes cancelling across effects still leave it set. The record tier alone uses the consolidated batch delta (moved_records). record_fingerprints and document_content are gone.').
decision('improvise-bw4p',zset_send_by_arena,'Circuit is Send and not Sync with no lock: it owns every edge slot, input pending delta and sink sum in one Vec<Box<dyn Any + Send>> arena, nodes hold typed ids, and Stream/Input/Output are Copy ids used through the circuit (current/push/take; a foreign handle panics). A closure can therefore not read a stream during a step. Cost about 7-9% per tick, measured and kept (context/code/zset.md, Threads). Not Sync is pinned by a_circuit_is_not_sync.').
decision('improvise-bw4p',multithreading_is_scheduling,'User ruling 2026-10-11: a sub-circuit stays synchronous and single-threaded, the edge (zset::edge) is the only channel that crosses threads, and a small executor (improvise-incremental sched.rs) decides which thread runs which unit. Native threads only: Pool and the blocking calls are cfg(not(wasm32)). A ruling recorded in context/code, not an ADR amendment.').
decision('improvise-bw4p',edge_join_by_correction,'A zset edge receiver joins a sender incarnation only by the answer to its latest request: a token per receiver incarnation (EdgeSource::new seeds it from a fresh base; restart keeps the counter), echoed in the Correction. A frame from an unjoined epoch only marks stale. Two earlier designs, joining by a first delta with from == 0 and a left list of incarnations, were wrong. The host timeout (connection_lost) must exceed the round trip (context/code/zset.md, Edges).').
decision('improvise-bw4p',sched_worker_survives_any_turn_panic,'A unit turn runs outside the executor lock. Its panic is caught and the unit buried (never run or kicked again, recorded in Executor::panics), and a dead unit is dropped inside catch_unwind so a Drop that panics cannot kill the worker. wait_idle does not hang on a dead unit. OPEN: a panic_any payload whose own Drop panics is dropped outside catch_unwind (improvise-bw4p.40).').
decision('improvise-bw4p.5',zset_rollback_is_an_undo_log,'Circuit::begin/commit/rollback keep an undo log of what the steps touch, not a snapshot; rollback replays newest first so no undo leaves i64; a Rebuild is bound to its circuit and a rollback that took its chunks interrupts it for good (the circuit counts undone steps); take an Output only after commit. A step that panics outside a transaction leaves the circuit unusable. zset-ffi exposes zs_circuit_begin/commit/rollback with ZS_ERR_TRANSACTION and ZS_ERR_INTERRUPTED.').
decision('improvise-rnak',a_change_source_shows_state_as_of_its_last_drain,'A ChangeSource shows its cells as of its last drain_changes, so a snapshot read now plus changes drained later counts no change twice or not at all. A feed has one drainer: two backends over one feed split the changes (test a_feed_has_one_drainer). Model::over(source) is read-only in every build (assert, not debug_assert) and the evaluator is still the single Model one.').
decision('improvise-rnak',an_exactness_test_needs_an_inexact_input,'A test that a sum or merge is exact must feed values whose float sum is order-dependent or inexact; with exactly representable inputs a float implementation passes (found reviewing Summary merges). Summary::from_parts refuses states no sequence of values could produce rather than repairing them.').
decision('improvise-bw4p.20',eager_math_fixed,'User ruling 2026-10-10: do not reproduce math bugs in Eager. Min/Max order by total_cmp over non-NaN values (-0.0 below +0.0, platform independent); Min/Max over only NaN is NaN; the formula fixed point compares with model::types::settled (bits, every NaN one value) so a stable NaN is not circular and a zero sign flip is a change; empty SUM is +0.0. Min/Max skip NaN while Sum/Avg propagate it (kept, a product question).').
decision('improvise-bw4p.30',stem_order_is_a_known_evaluator_defect,'recompute_formulas updates its cache in place in stem order and stops at 16 passes, so two sources holding the same cells in different orders can disagree. This is an evaluator defect, not a source contract: distinct_without returns first-seen order and a source with no order of its own should list stems in a stable one until it is fixed.').
wire_carries(command,both_directions,'user intent up, projection commands down').
wire_carries(snapshot,on_connect_only,'improvise-q08: full ViewState + render cache filled from current viewport').
wire_carries(command,both_directions,'user intent client->server, projections server->client').
@@ -660,6 +669,8 @@ crate_depends_on(improvise_command,zset).
crate_depends_on(improvise_command,improvise_incremental).
crate_depends_on(improvise_gp,improvise_core).
crate_depends_on(improvise_command,improvise_gp).
crate_depends_on(improvise_core,numtower).
crate_depends_on(improvise_incremental,numtower).
depends_transitively(A,B):-depends_via(A,B,[A]).
depends_via(A,B,C):-crate_depends_on(A,B).
depends_via(A,B,C):-crate_depends_on(A,D), \+memberchk(D,C),depends_via(D,B,[D|C]).