This library is in flux. APIs may change without notice. Generated from source with koruc 0.1.7 on 11/4/2026.

Store

import std/store

Koru Standard Library: Reactive Stores

store.kz · 13 tors

Koru Standard Library: Reactive Stores · 64 more lines
Koru Standard Library: Reactive Stores Application state as a compiled-reactivity substrate. The FULL design — 9 rulings, adversary-stamped theses, the open queue — lives in tests/regression/600_STDLIB/690_STORE/DESIGN.md (delete-when-pinned). The pins (690_001..008) are the acceptance tests; this file grows until they green, rung by rung. THE SPINE (ruled 2026-07-04): - A store is COMPTIME-NAMED and second-class (ruling 9): never a value, never passed, never nested. `create(game) { ... }` declares name + shape + seed; anyone anywhere links by name. - `stored { game.field: expr }` is the SOLE write path. - Subscriptions (`watch`) compile INTO the write path — tap-style, producer owns the guard, NO runtime registry (ruling 7). - Ruling (f): all writes route through ONE centralizing write-subflow per store; watches/interceptors/guards splice there ONCE. - Writes interleave, never overlap: write + full cascade is the atomicity unit ((h) lean); birth is not a write (O9 lean — the seed is stored in memory, never dispatched as an tor). RUNG ONE — COMPLETE (690_001-004 green runners, 690_006 green designed rejection; SHOWN 2026-07-05). The (f) architecture: `create` is the coordinator. Per store it appends FIVE units: 1. The module-scope typed cell (capture's @Type builder, host_line). 2. An APPLY tor — one terminal branch per field, announcing what was written (`| entities i64`; with an `updated` interceptor the payload is `{ old, new }` — the (c) usage-synthesis lean). 3. The apply |zig proc — switch on the comptime-constant field index, write the cell, return the field's branch with the new value. (kernel's raw-Zig generated-proc precedent.) 4. The WRITE tor — the store's sole write surface, void. 5. The write tor's implementing FLOW — head invokes apply; its continuation arms ARE the transplanted interceptor+watch branches, interceptors sequenced first ((h): watches observe settled state), guards riding as arm conditions (producer owns the if). THIS is the ruling-(f) centralizing write-subflow: bodies splice here ONCE; the atomicity lock and T8 backend cells will live in this body. A nested `stored` inside an interceptor body compiles into a call into the OTHER store's write-subflow — the cascade is ordinary calls through generated subflows, no runtime registry. `stored` rewrites each write site into a plain invocation of the write tor — an ordinary flow, emitted inside a function like any call. `watch` sites run the transplant-purity check (ruling (a): free names ⊆ own bindings ∪ comptime-known — koru-level diagnostic, 690_006) and self-erase once the coordinator has spliced their bodies. STILL WALLED (loud, never silent — KORU047 doctrine): - Multiple watches on one field — needs taps' sequencing splice. - Multi-field `stored` blocks — the (i) chain-envelope, rung two. - Mixing `updated {old,new}` with field-level consumers on one store. - Guarded watch on a field that also has interceptors. - Nested (mid-flow) watch splicing; watch-before-create source order. - Non-i64 fields; guarded interceptors; `inserted`/`removed` (rung 2). ARCHITECTURE NOTES: - Generated decls follow kernel's precedent exactly (event_decl + proc_decl with raw-Zig body, appended as top-level items; the emitter finds impl_of flows by scanning items at emission time). - Watch collection is kernel's findShapeSource pattern: the transform receives *const Program and walks items for `std/store:watch(name)` flows. Source order: create must precede its watches (loud wall otherwise — the walker transforms in program order, and the coordinator must still be able to see untransformed watch bodies). - Validation happens IN the transforms (loud refusal), not the shape checker — checkers run after transforms (capture precedent).

~part new koru_std/store.new.kz

Koru Standard Library: Reactive Stores — the `new` event. Joined via `~part new` in store.kz; merged into the store module at load. STORE.CREATE — declare + instantiate a store; the (f) coordinator std/store:new(game) { entities: 0[i64] } — capacity-1 VALUE std/store:new(pool, capacity: 64) { hp: i64 } — CONTAINER (rows) Name arg + seed block (kernel:shape's surface). CAPACITY selects the shape (690_050 ruling): default 1 → reactive value, > 1 → container. A field is bare-typed (`hp: i64`) or carries a default via the bracket annotation (`hp: 100[i64]` — same parser as const/capture); defaults are orthogonal to shape.

new

keywordcomptimetransform koru_std/store.new.kz:17

~part pwalk koru_std/store.pwalk.kz

Koru Standard Library: the `pwalk` part of store.kz. Joined via `~part pwalk` in store.kz; merged into the module at load. The plural-store whole-program reference walk: `storeRefsContH` / `storeRefsFlowH`, created for `new`'s declaring-module namespace (empty prefixes — a plural-walk reader sits where the store was declared). The identity-store walk is `Rewrite.rewriteCont` in store.new.kz; the two enumerate the same AST positions and drift is the known defect shape — `frag-a-fix-lands-in-one-lowering-path`. A whole-program walk over one flow, lowering every text slot an expression may stand in. `scope` carries the program's store names with the prefix each needs (empty here — the plural walk reads from the declaring module's own namespace).

~part neworder koru_std/store.neworder.kz

Koru Standard Library: the `neworder` part of store.new.kz — the preorder sweep body (plain and `order:`-sifted variants) for all three hosts, plus `order:` clause validation. Joined via `~part neworder` in store.kz; merged into the module at load.

~part emitnames koru_std/store.emitnames.kz

Koru Standard Library: the `emitnames` part of store.kz — joined via `~part emitnames`; members land in koru_store. Names that reach the emitted program: a store's `new` argument mints `__KoruStoreT_<name>` as a Zig declaration, and every qualifier helper spells the namespace the synthesized units are addressed under. A name that cannot be spelled by the target (or its caller) dies inside generated code on a symbol the author never wrote — so legality is checked here, where the name is taken, not where it lands. A store name is pasted verbatim into `const __KoruStoreT_<name>` in the emitted Zig — so its grammar is the TARGET's identifier grammar, not Koru's kebab: letter/`_` first, then letters/digits/`_`. Anything else (`evil(x)`, `my store`, `9lives`) makes Zig die inside generated code on a symbol the author never wrote.

~part hstruct koru_std/store.hstruct.kz

Koru Standard Library: the `hstruct` part of store.kz. Joined via `~part hstruct` in store.kz; merged into the module at load. The handle-table slice of a needs-handles store struct: the slot arrays, the identity flag, the materialise helper, and the row_of/resolve/handle_of methods. Emitted as one block — the text is the contract a thousand call sites lean on.

~part view koru_std/store.view.kz

Koru Standard Library: Reactive Stores — the `view` tor. Joined via `~part view` in store.kz; merged into the store module at load. STORE.VIEW — a vocabulary of stores, projected for iteration std/store:view(Entities) { Player, Enemy } A store-view is not a container: it has no capacity, no allocation, no insert, and no SoA cell. The rows live in the member stores. It registers the kind vocabulary and the folded shared schema.

view

keywordcomptimetransform koru_std/store.view.kz:14

~part stored koru_std/store.stored.kz

Koru Standard Library: Reactive Stores — the `stored` event. Joined via `~part stored` in store.kz; merged into the store module at load. STORE.STORED — the sole write path: an ordinary call into the subflow std/store:stored { game.entities: game.entities + 1 } Rewritten into `__store_write_game(field: <idx>, value: <expr'>)` where <expr'> has dotted store reads rewritten to the cell. The replacement is a real flow, so it is emitted inside a function like any other call.

stored

keywordcomptimetransform koru_std/store.stored.kz:14

~part default koru_std/store.default.kz

Koru Standard Library: Reactive Stores — the `default` tor. Joined via `~part default` in store.kz; merged into the store module at load. STORE.DEFAULT — the bare reference form as a program-wide reactive attach std/store(enemies) ! hp h |> … // a standing rule, from anywhere `std/store(name)` is the store's reference; `std/store(name) ! arms` attaches those arms as standing reactive rules — a program-wide `watch`. This is a `[pre]`-phase rewrite: it renames the bare `default` invocation to `watch` BEFORE `create` scans for watch arms, so the entire (already-green) watch machinery — create-time splice into the write-subflow, transplant-purity, self-erase — handles it with no duplication. Reactive rules are top-level only; they are standing rules, not mid-flow steps.

default

keywordcomptimetransformpre koru_std/store.default.kz:19

~part watch koru_std/store.watch.kz

Koru Standard Library: Reactive Stores — the `watch` tor. Joined via `~part watch` in store.kz; merged into the store module at load. STORE.WATCH — subscriptions; bodies are transplanted by the coordinator By the time this transform fires for a well-formed program, create has already spliced this watch's branches into the write-subflow — the site self-erases. Firing with the store's create still untransformed means the watch precedes its create in source (a rung-one ordering wall); no create anywhere is a plain unknown-store diagnostic.

watch

keywordcomptimetransform koru_std/store.watch.kz:14

~part insert koru_std/store.insert.kz

Koru Standard Library: Reactive Stores — the `insert` tor. Joined via `~part insert` in store.kz; merged into the store module at load. STORE.INSERT — append a row to a plural store (rung two) std/store:insert(game) { hp: 30, kind: 1 } — bare append std/store:insert(game) { hp: 50, kind: 1 } | row r |> … — handle form Rewritten into `__store_insert_<s>(…)` (void) or `__store_inserth_<s>(…)` (`| row i64`) — the site's own continuations ride along. `__site_line` carries the site's source position so standing query enters stay honest about program order (a query only hears inserts BELOW it in source).

insert

keywordcomptimetransform koru_std/store.insert.kz:16

~part rule koru_std/store.rule.kz

Koru Standard Library: Reactive Stores — the `rule` tor. Joined via `~part rule` in store.kz; merged into the store module at load. STORE.QUERY — row-level subscription + imperative sweep (rung two) The coordinator (create) has already transplanted this site's projection, guard, and body into the per-line qrow/qbody units and spliced standing enters into the insert path. The site itself becomes the SWEEP over the rows that exist when its program position executes ((l) lean: the imperative sweep IS the stripe).

rule

keywordcomptimetransformclaims_descendants koru_std/store.rule.kz:14

~part query koru_std/store.query.kz

Koru Standard Library: Reactive Stores — the `query` tor. Joined via `~part query` in store.kz; merged into the store module at load. `claims_descendants`: query MUST fire before its own `! query <row> |> body` branch is walked. Otherwise print.ln (deeper, so depth-first-first) resolves the body's `{{ field }}` holes while the row binding isn't in scope yet (pre-transplant), leaving a raw template. query dodges this by having `create` drive the transplant early (on `new`); sweep drives its OWN transplant at the site, so it must claim its descendants to win the same race.

query

keywordcomptimetransformclaims_descendants koru_std/store.query.kz:10

~part preorder koru_std/store.preorder.kz

Koru Standard Library: Reactive Stores — the `preorder` tor. Joined via `~part preorder` in store.kz; merged into the store module at load. STORE.PREORDER — DFS pre-order forest walk over a [tree] store std/store:preorder(tree) ! preorder { entity.val } |> … The tree-store traversal surface (695_STORE_TREE, TT5). The coordinator (create) has already transplanted this site's projection/guard/body into qrow/qbody units — identical to query — and emitted a DFS pre-order sweep over the synthesized `parent` column (roots first, insertion order; each node before its children). The site itself becomes that sweep's call. Preorder on a non-[tree] store is rejected by the coordinator with a teaching diagnostic (no parent column to walk).

preorder

keywordcomptimetransformclaims_descendants koru_std/store.preorder.kz:19

~part preordertail koru_std/store.preordertail.kz

Koru Standard Library: the `tail` part of store.preorder.kz — the preorder site's continuation split and replacement assembly. Joined via `~part tail` in store.preorder.kz; merged into the module at load.

~part take koru_std/store.take.kz

Koru Standard Library: Reactive Stores — the `take` tor. Joined via `~part take` in store.kz; merged into the store module at load. STORE.TAKE — extract a row with ownership through the handle head std/store:take(game[r]) | item i |> … Swap-remove (legal: position is never identity — O2/O10.iii). Compiles to `__store_take_<s>(row: <handle>)`; the `| item {fields}` branch carries the row out. Obligation wiring (a taken row must be consumed or given back — 690_007/690_015) rides on the take tor's phantom.

take

keywordcomptimetransform koru_std/store.take.kz:15

~part clear koru_std/store.clear.kz

Koru Standard Library: Reactive Stores — the `clear` tor. Joined via `~part clear` in store.kz; merged into the store module at load. std/store:clear(s) — empty a plural store in ONE step. The bulk twin of `take`. Where `take` removes one row and fires `removed`, `clear` removes every row and fires `cleared` once. Each removal verb has its own arm; neither fires the other's, which is what lets a bulk removal stay bulk instead of degenerating into a thousand per-row tors. Outstanding handles go stale across it (the generation of every live slot is bumped), so the stale-handle trap 690_115 pins still fires afterwards. Refused where the meaning would be ambiguous rather than guessed at: a store with owned columns keeps `take` plus `! discharge` (obligations discharge one at a time, and a bulk reset would drop them silently), and a store with a `! removed` arm must declare `! cleared` to say what the aggregate means.

clear

keywordcomptimetransform koru_std/store.clear.kz:19

~part stripe koru_std/store.stripe.kz

Koru Standard Library: Reactive Stores — the `stripe` tor. Joined via `~part stripe` in store.kz; merged into the store module at load.

stripe

keywordcomptimetransform koru_std/store.stripe.kz:5

~part qrewrite koru_std/store.qrewrite.kz

Koru Standard Library: the `qrewrite` part of store.kz. Joined via `~part qrewrite` in store.kz; merged into the module at load. The query arm's row-binding rewriter — lifted out of the transform fn to file scope so store.query.kz stays under its line baseline. Self-contained: every dependency arrives as a parameter.

~part cursor koru_std/store.cursor.kz

Koru Standard Library: the `cursor` part of store.kz. Joined via `~part cursor` in store.kz; merged into the module at load. The sweep cursor's spellings and cursor-derived captures — lifted out of store.qrewrite.kz so both parts stay under their line baselines. Self-contained: every dependency arrives as a parameter or a module-scope name. A dense cursor is `usize` end to end, so a column read indexes with it directly.

~part qcaps koru_std/store.qcaps.kz

Koru Standard Library: the `qcaps` part of store.kz. Joined via `~part qcaps` in store.kz; merged into the module at load. The query sweep's capture-collection helpers — lifted out of the query proc to module scope so store.query.kz stays under its line baseline. Self-contained: every dependency arrives as a parameter.

~part qbinds koru_std/store.qbinds.kz

Koru Standard Library: the `qbinds` part of store.kz. Joined via `~part qbinds` in store.kz; merged into the store module at load. The path half of sweep capture collection — the walk that answers "which enclosing names can this transplanted body see" (arm bindings, destructure fields, mid-pipe return binds, `! each` loop items) and the pick that turns in-scope into captured once a body's own refs are known. `Cap` keeps the Bind record and the reference scans; the walk lives here so qcaps stays under its line pin.

~part retqual koru_std/store.retqual.kz

Koru Standard Library: the `retqual` part of store.kz. Joined via `~part retqual` in store.kz; merged into the module at load. Return- and branch-type resolution for the query sweep's captures — the sibling of Cap in qcaps.kz, lifted for the same line wall. These helpers walk the program items and answer "what type does this tor's return (or this branch's payload) yield?", phantoms re-qualified to the DECLARING module's namespace so a captured binding arrives tracked. Self-contained: every dependency arrives as a parameter.

~part pverbs koru_std/store.pverbs.kz

Koru Standard Library: the `pverbs` part of store.kz. Joined via `~part pverbs` in store.kz; merged into the module at load. The pump-participant verbs (`! step`/`! wait`/`! live` arms and the `<s>-step`/`<s>-live`/`<s>-wait` generated units) — lifted out of the `new` transform to keep store.new.kz under its line baseline. Self-contained: every dependency arrives as a parameter (the qcaps rule); the proc-local helper structs (`H`, `Usage`, the owned-column record) arrive as `anytype`. KORU100 for interceptor payloads: a bound row field must be USED in the body (or discarded with `_`). flow_checker's unused-binding pass skips `[transform]` invocations, and `std/store:new` is one, so the store transform enforces it here — scanning the body's expression / source text for the field name at a word boundary.

~part sitetag koru_std/store.sitetag.kz

Koru Standard Library: Reactive Stores — synthesized-name site tags. Joined via `~part sitetag` in store.kz; merged into the store module at load. The file tag a synthesized store unit carries in its minted name. Query/sweep declarations emit into the STORE's home scope no matter which file armed them, so a name keyed on store+line alone collides the moment two files arm the same store on the same source line (690_306: `sim/` and `ext/` each `! query` `items` at line 14 → one `__store_sweepbody_items_L14` for two bodies). `flow.module` cannot discriminate — it is the file BASENAME, identical for `sim/index.k` and `ext/index.k` — so the tag comes from the site's full path: parent-dir + stem keeps it readable; a short path hash keeps it unique when two roots carry the same tail (vendored copies of one file inside a program).

~part explain koru_std/store.explain.kz

Koru Standard Library: the `explain` part of store — joined via `~part explain` in store.kz; members land in koru_store. A store's truth is scattered: `std/store:new` declares columns and interceptor arms, `std/store:insert`/`query`/`take`/`clear`/`stripe` sites reference it by name, standing watches ride the bare `std/store(name)` form, and `! step`/`! wait` turn the store into a pump participant exposing `<s>-step`/`<s>-live`/`<s>-wait`. The explainer folds the sites — the member block through the same `struct_literal.parseFields` the transform calls — and reports the composition: capacity, columns, interceptors, site counts, pump verbs, member-proto facets (refine's own `metFields` fold), and each query site's plan — index routing decided by the transform's own fold (SPlan). The site fold lives in `sites` (SX), the plan fold in `plan` (SPlan). Then it shows the work: the program is cloned, the real transform pass runs over the clone, and the items the transforms minted print through the canonical AST printer (src/ast_printer.zig). A store's truth is `__`-prefixed -- `__store_apply_<s>` / `__store_write_<s>` / `__store_qsweep_<s>` land in the program with no spelling the source ever carried -- so the `elaborated` sections below cannot drift from the transform: they ARE the transform's output.

explain-store

comptimeexplainer koru_std/store.explain.kz:144

~part sites koru_std/store.sites.kz

Koru Standard Library: the `sites` part of store — joined via `~part sites` in store.kz; members land in koru_store. The site fold shared by `store.explain.kz`'s explainer — a counted row's `at` witnesses are the sites it counted (`inserts = 1 [deadb]`).

~part leaf koru_std/store.leaf.kz

Koru Standard Library: leaf-column machinery — joined via `~part leaf` in store.kz; members land in koru_store. A seed field that names a compound proto dissolves into path-named leaf columns (`left: Limb` -> `left.health`). TermRef resolves terminal scalars, MemberRef finds the compound declaration, ProtoExpander does the recursive flatten and records each leaf's provenance — which proto field it expands — for `insert's facet guards and the explainer's enforcement row.

~part index koru_std/store.index.kz

Koru Standard Library: Reactive Stores — the `index` part. Joined via `~part index` in store.kz; merged into the store module at load. STORE.INDEX — discovery for `std/indexes:store(<store>, <column>)` The declaration is pure AST-data: std/indexes's `[norun]` `store` tor claims the site, it never executes, and the node stays in program.items for the whole transform pass — the AST is the registry. These helpers are how the verb transforms ask "is my store indexed, and on which column." The map is key→ORDERED HANDLE LIST — every live row carrying the key, in join order. Swap-remove needs no moved-row fixup (a row's handle is unchanged when it moves dense slots — 690_092) and a taken row's entry needs no fixup either: the dead handle resolves to no row through the generational path (690_115/116) and every reader skips it. Maintenance is emitted inside the verbs — an outside watcher could never see the displaced row; no tor fires for it. The one declaration serves both consumers: `! first` answers the LOWEST dense live member (the sweep's first-match parity) and `! query <row> when <row>.<col> == <k>` walks the bucket instead of sweeping — the membership IS the guard. Membership order, not dense order, is the routed query's visit order: identical to the sweep's until a take reshuffles dense slots, and the divergence is pinned.

~part indexwalk koru_std/store.indexwalk.kz

Koru Standard Library: Reactive Stores — the `indexwalk` part. Joined via `~part indexwalk` in store.kz; merged into the store module at load. STORE.INDEXWALK — the `! query` bucket walk for an indexed guard `! query <row> when <row>.<col> == <k>` on an `std/indexes`-declared store walks the key's bucket instead of sweeping — the membership IS the guard. Two walk shapes, picked by what the body can reach: a body that cannot disturb the bucket gets a `for` over the captured slice (one map probe for the whole query); a body that can gets a `while` whose post-body survival check re-reads the bucket and re-examines the slot a moved member vacated — 690_031's re-check contract at bucket granularity. Visit order under the route is bucket (join) order. The shared row-fire emit (`fireRow`) lives in `store.cols.kz` — it serves the sweep and both walks, and the wall keeps the emit helpers together.

~part oindex koru_std/store.oindex.kz

Koru Standard Library: the `oindex` part of store.kz. Joined via `~part oindex` in store.kz; merged into the module at load. The ordered index — `std/indexes:ordered(<store>, <col>)`. Same AST-data declaration slot and one-decl-per-store rule as `std/indexes:store`; the difference is the backing structure: a sorted directory of `{ key, members }` entries instead of a key→bucket hash map. `==` is a binary search; a range guard is a bound plus a walk — one maintenance path serves both, which is why the declaration is a widening, not a sibling. Zig-target only at this rung; fieldSpec refuses the decl on js/cs before any of this code is reached. The comparison a routed guard names. `eq` is the only route an equality index serves; the ordered directory serves all five.

~part idecls koru_std/store.idecls.kz

Koru Standard Library: Reactive Stores — the `idecls` part. Joined via `~part idecls` in store.kz; merged into the store module at load. STORE.IDECLS — `std/indexes:store` declaration discovery + the new-site spec The declaration is pure AST-data (store.index.kz): a `~[norun]` tor claims the site and the node stays in program.items — the AST is the registry. This part reads that registry: every `std/indexes:store(<s>, <col>)` naming a store, and the whole decision `new`'s SoA-cell emit makes from them — the backing-map field text and which seed column it keys on, or the refusal. One declaration per store is the ruling today: a second claim is refused at ITS OWN location — the later declaration is the offender, not the store (pin 690_328). The first-match walk it replaced let a second claim sit dead — no field, no machinery, no diagnostic.

~part qnone koru_std/store.qnone.kz

Koru Standard Library: Reactive Stores — the `| none` arm emit. Joined via `~part qnone` in store.kz; merged into the store module at load. STORE.QUERY.NONE — the `| none` arm's emitted-body builder `| none` is the absent case of a `! first` site: its body transplants into its own tor exactly as the sweep arm does, minus the row — no projections, no cursor, captures only. The call lands after the loop under `if (!__koru_found)` (emitted by the query transform on both loop paths). This builder owns the body's construction end to end: mint the __store_nonebody_* event + impl flow pair into `appended`, hand back the body's name, the capture-record text for the call, and the lexical count the site's own capture bookkeeping needs.

~part qmiss koru_std/store.qmiss.kz

Koru Standard Library: Reactive Stores — query miss classification. Joined via `~part qmiss` in store.kz; merged into the store module at load. "Unknown plural store" was one refusal conflating distinct misses — a name nobody declared, a query that precedes its store's create in source, a capacity-1 value store, and declared-as-another-kind names (a tor, a store view) — the last family lives in the `qmisskind` part. The markers mirror stored.kz/watch.kz: `__store_write_<s>` is the value tier's coordinated write tor, and a still-untransformed `std/store:new` flow is a create sitting BELOW this query — a create that already ran lowered to __store_* markers instead.

~part qmisskind koru_std/store.qmisskind.kz

Koru Standard Library: Reactive Stores — query miss kind classification. Joined via `~part qmisskind` in store.kz; merged into the store module at load. The fourth and fifth misses under "unknown plural store": the name IS declared — as a tor or a store view — or is genuinely absent / a flow-local binding this module-scope scan cannot see. KORU161's dominant corpus sub-family (~30 rows, 69% teach-miss) was exactly this conflation: query() aimed at a name that exists but isn't a container, told only that no `std/store:new` exists — which taught "the name is wrong" when the tier was. Naming the kind is the fix: a tor is called, a view is a projection, neither sweeps.

~part gate koru_std/store.gate.kz

Koru Standard Library: the `gate` part of store.kz. Joined via `~part gate` in store.kz; merged into the module at load. The handle-observation gate and the take predicate it builds on — lifted out of store.new.kz so both parts stay under their line baselines. Self-contained: everything arrives as a parameter or a module-scope name (`ast`, `StoreIndexDecls` — the part merge makes them visible here). Can ANY row of this store be removed while a rule pass is running? Only a `take` can remove one, and a take reached through a CALLED flow is invisible to a scan of the rule's own arm — so the question is asked of the WHOLE PROGRAM, not of the arm. A program that never mentions take cannot remove a row from anywhere, by construction, and every one of its rule passes can use the query path's `for (0..len)` instead of the removal-tolerant `while`. The question is whether a row of THIS store can be removed while one of its passes is running. The old predicate asked something far cruder — `std.mem.indexOf(text, "take") != null` over every condition, path segment and argument in the program. MEASURED 2026-08-03, and it is worth 6.1x: one match flips every standing rule in the program off the dense cursor onto the handle round-trip, and that round-trip's @panic sites forbid vectorization (0.77 -> 4.8 cycles/row, rf_stripe_1 at 10k rows, 2260 -> 13806 ns/iter, checksum oracle identical). What tripped it: - `taken`, the store's OWN obligation state, so any program with an [entity(...)] discharger de-optimized itself; - a take on a COMPLETELY UNRELATED store; - the word `mistake` inside a string literal, measured directly. The grep itself is free; it is the wrong ANSWER that costs 6.1x. Now: an actual `std/store:take` invocation whose addressing head names THIS store, in either spelling (raw, or already lowered to `__store_take_<s>` if this scan runs after that rewrite). Per-ARM since 690_301: the reachability machinery — the arm's own continuation tree plus every subflow impl it invokes — is ast_functional.armReachesInvocation; what lives here is the predicate that knows what a take on THIS store spells like. Anything unparseable answers YES and stays conservative. Finds a named arm and peels tap-inserted wrappers — shared by the qsite walker (store.new.kz) and the gate's querySite check.

~part bulk koru_std/store.bulk.kz

Koru Standard Library: the `bulk` part of store.kz. Joined via `~part bulk` in store.kz; merged into the module at load. Bulk append — `for(lo..hi) ! each i |> insert(s){fields}` lowered to a hoisted capacity check, per-column writes at `base + j`, and one `len += n`. The per-row path's `len += 1` is a loop-carried store no optimizer can reassociate past the per-row capacity @panic; measured ~294us -> ~89us on the add_remove fill by hand-editing the emitted binary's loop (same checksum, same build — the marshal shape was already free, the serial len was not). Neither end of the pattern can see the other: `std/store:insert`'s transform is site-local, and `std/control:for`'s Liquid template holds its body as an opaque `__koru_inline_scoped_N` marker. `new`'s whole-program scan is the one place both sides are visible, so the recognizer lives here. Zig only — `InlineCode` carries no lane and this text IS Zig, so `proc new|js` gates it off at the call site. Every doubt declines the site; a declined site stays a per-row insert and is correct by construction. Handle-bearing stores keep the tier: the batch mints the same slot sequence the per-row path would — freelist pops in LIFO order (`free[frem-1-j]`), then bump-allocations (`next+k`) — so handle values, freelist order, and generation counters are bit-identical. What a batch cannot reproduce is a reactive enter: a rule or query site fires per insert at sites BELOW its declaration (the emitter's `__site_line > qs.line`), so `match` declines any counted-for whose insert line follows a non-preorder qsite. The text-producing half — token scanners, the insert-field match, the Zig block itself — lives in `store.bulkemit.kz` (`BulkEmit`), split under the line-baseline wall.

~part bulkemit koru_std/store.bulkemit.kz

Koru Standard Library: the `bulkemit` part of store.kz. Joined via `~part bulkemit` in store.kz; merged into the module at load. The bulk-append emit half — token scanners, the insert-field match, and the host dispatch + Zig text (cs's `bulkEmitCs` via `emitFor`).

~part bulkjoin koru_std/store.bulkjoin.kz

Koru Standard Library: the `bulkjoin` part of store.kz. Joined via `~part bulkjoin` in store.kz; merged into the module at load. The per-row emission of a bulk insert: column stores, and — when the store carries `std/indexes:store` — the index join that appends each row's handle to the right key bucket.

~part plan koru_std/store.plan.kz

Koru Standard Library: the `plan` part of store — joined via `~part plan` in store.kz; members land in koru_store. The explainer's SQL-EXPLAIN rung: which store carries a declared index, and per query site the plan the `query` transform would emit — sweep, early-exit sweep, index lookup, or refusal. The ruling (frag: an explainer runs the transform's fold, not a second reading) means the plan comes from the very functions the transform calls — the same `findArm` over the same continuations, the same `rewriteIsGuard`, the same `SRewrite.refs` lowering of the `when` guard, and the same `StoreIndex.guardRoute` routing decision — never a re-read of the source condition. Refusal wording is shared, not mirrored: the KORU161 texts below are the strings the transform itself refuses with.

~part drain koru_std/store.drain.kz

Koru Standard Library: the `drain` part of store.kz. Joined via `~part drain` in store.kz; merged into the module at load. Drain — a rule whose row body is exactly `take(s[e])` with a discard `| item` removes every row the invoked sweep visits. Per-row take reads every column into the payload and swap-writes the last row's columns into the freed slot — work for the payload's sake and for survivor liveness. A drain has neither. The teardown is the clear unit's canonical reset, not a walk of take's freelist pushes: every issued slot's generation bumps once (`0..hslot_next` covers live rows AND slots freed by earlier takes), then `hslot_next`, `free_len` and `len` drop to zero and `ident` re-arms. Materializing the freelist paid three costs for one observable difference — refilled rows take slots in fresh order rather than take's LIFO pop order: the fill loop itself, a cold page-fault pass over `hslot_free`, and `ident` flipping false FOREVER, which degraded every later drain/refill to the scalar slot-mapping path. `clear` already blesses reset order, and the slot SET reissued is identical either way. Dead slot bytes (`row_hslot`, `hslot_row`, stale freelist entries) stay unreachable post-reset: resolve's `slot < hslot_next` rejects them, and the next materialize() rebuilds the mapping for live rows only. Every doubt declines the site: `when` makes the walk selective, a `| item` read makes materialisation load-bearing, an owned column discharges one obligation at a time, a `! removed` arm fires per row. An index column is NO doubt — take reseats nothing and dead handles idle in buckets — so a teardown leaves the index exactly as sequential take would. A declined site stays per-row take.

~part expand koru_std/store.expand.kz

Koru Standard Library: compound-expansion machinery — joined via `~part expand` in store.kz; members land in koru_store. ProtoExpander does the recursive flatten of a compound seed member into leaf columns (with `<:` parents merged ahead of the block) and records each leaf's provenance for insert's facet guards and the explainer's enforcement row. MemberRef/TermRef stay in store.leaf.kz.

~part kinds koru_std/store.kinds.kz

Koru Standard Library: the union-member kind vocabulary — joined via `~part kinds` in store.kz; members land in koru_store. A member is a seed field naming a compound proto; ordinals are seed order, 1-based. This part owns member detection (live decls and erased markers), per-member leaf schemas, `is`-guard narrowing, the demanded-tag check, and the private-leaf refusal — shared by new, insert, query, plan. Union-member machinery (shared by `new` and `insert` — one definition, no per-proc copies; the foreign collector precedent). A member is a seed field naming a compound proto; ordinals are seed order, 1-based.

~part refs koru_std/store.refs.kz

Koru Standard Library: Reactive Stores — the `refs` part. Joined via `~part refs` in store.kz; merged into the store module at load. `ref(X)` leaf columns (the proto.OOP rung): the material is i64 — the column IS the row handle — and the declared target is validated here and persisted on the create-site marker (`; ref col->Target`) so the typed edge survives the seed's self-erase. Pinned: 698_009 (insert a minted handle, follow it cross-store, write through), 698_011 (an unknown seed target refuses at this gate).

~part refhome koru_std/store.refhome.kz

Koru Standard Library: Reactive Stores — the `refhome` part. Joined via `~part refhome` in store.kz; merged into the store module at load. The HOME check for `ref(T)` columns: a handle written into `col: ref(T)` must carry the brand of a store that HOLDS T — a plural store whose expanded leaf set carries T's flat fields. The test is field-set subsumption, not name-matching, so a `<:`-extended proto's store is a home of its parents (698_014) and erased protos need no parent record — their markers already arrive merged. Homes enumerate from the whole program: live `std/store:new` decls expand their seeds; consumed ones carry `; fields` on the create marker. The guard fn each store emits (`__koru_home_<store>_<col>`) compares the handle's brand byte against every home's `__koru_brand`, skipping lean stores via @hasDecl — a store that never mints handles is no home. Pinned: 698_012/013 (foreign handle traps at insert/stored), 698_015 (-1 is the unset sentinel), 698_016 (no home refuses at create).

~part refhomeapi koru_std/store.refhomeapi.kz

Koru Standard Library: Reactive Stores — the `refhomeapi` part. Joined via `~part refhomeapi` in store.kz; merged into the store module at load. The cross-consumer entry point for ref(T) home enumeration: the `qualifier:name` split lives here exactly once, then defers to StoreRefHome.homes. Every consumer that materializes a `ref(T)` field — a store's columns, a list's push — asks this one authority who the homes are; the answer is a fact about the program, not the consumer.

~part keyed koru_std/store.keyed.kz

Koru Standard Library: Reactive Stores — the `keyed` part. Joined via `~part keyed` in store.kz; merged into the store module at load. `store[key: value]` is a pinned hole (690_018): `std/store:new` accepts `key:` and emits ZERO lookup machinery — no key->row map, nothing maintained at insert/take/swap-remove — and every `store[...]` consumer splices the bracket interior verbatim into `__koru_resolve`, source syntax in a host call position. The backend's `expected ')', found ':'` was the first diagnostic the surface ever produced. The law is honor or refuse (frag-std-store-design); honoring means a maintained key->handle map — the shape `std/indexes:store` already emits for `when` routing — so absent that machinery every consumer refuses, located, naming the pin and the working spelling. Residual hole: `storeIndexedRefs` (store.kz) is a pure text rewriter with no refusal channel — keyed reads reached through rule/query/guard positions still splice verbatim. Extend the wall when it gets one.

~part wait koru_std/store.wait.kz

Koru Standard Library: the `wait` part of store.kz. Joined via `~part wait` in store.kz; merged into the module at load. The store's `! wait` arm — the pump-participant interest contract. Where `! step` ASKS ("advance this row once"), `! wait` ANSWERS ("what would you block on"): the callee's RETURN TYPE is the vocabulary — `-> i32` is a descriptor to poll, `-> i128` a relative re-poll duration in ns, `-> { fd: i32, wait_ns: i128 }` both; an interest not declared means none (no sentinels to write). A pump that ends a pass all-idle collects one record per live row and blocks ONCE on the union — one poll over every fd, capped by the nearest wait_ns — instead of spinning or letting a single participant's sleep own the thread. `collect` runs the arm's contract checks and classifies which field sources the generated `__store_waitone_<s>` unit forwards into its normalized `{ fd, wait_ns }`; the refusal item on failure, or null with `wait_arm`/`wait_src` filled.

~part uncrossable koru_std/store.uncrossable.kz

Koru Standard Library: the `uncrossable` part of store — joined via `~part uncrossable` in store.kz; members land in koru_store. The void-graft boundary, both halves of it. Graft mints the synthesized VOID units store transforms lower arm bodies into — the `asVoidStep` sequential step every interceptor/watch body becomes and the `atEnds` splice that hangs grafted continuations on a chain's leaves. Post-graft such a body sits under `is_transformed_subtree`, which every checker skips by ruling (transformed subtrees are compiler-owned and pre-validated) — so the other half, refuseVoidArm, is the pre-graft wall: a `=>`/`->` inside a void-grafted arm names a branch of nothing and must be refused while the user-authored body is still visible. (kopium wired/holes/10: `=>` in a `! query` arm sailed through checking and died in emitted Zig, undiagnosed.) The walker and the diagnostic live in src/ast.zig (`refuseUncrossable`) — grid's sweep arms and channel's consumer arms share the same boundary and call it directly.

~part cols koru_std/store.cols.kz

Koru Standard Library: Reactive Stores — the `cols` part. Joined via `~part cols` in store.kz; merged into the store module at load. STORE.COLS — who is this store, column-wise, and how does a cell read One family of questions, all answered transform-order tolerantly — the coordinator may have run already (read the generated declarations) or not (read the untransformed create's seed block): storeMemberColumns — name/type/module_path/phantom per column storeFieldOrder — every SoA column, declaration order (incl. parent) storeInsertOrder — the insert surface (excl. a [tree] parent) charCap — is a column `char[N]`, and what is N cellRead — one column's projected read at `__koru_si` bareBindEnd — is a query's row binding in VALUE position here fireRow — the shared row-answer emit both query drivers land on

~part csemit koru_std/store.csemit.kz

Koru Standard Library: the `csemit` part of store.kz. Joined via `~part csemit` in store.kz; merged into the module at load. The C#-target emit bodies, lifted out of their topical parts as the third backend's arms grew them past the line wall: the handle-table struct slice (`hstructEmitCs`, once `HStruct.emitCs`) and the bulk-append emit (`bulkEmitCs`, once `BulkEmit.emitCs`). Each fn is reached through a member alias left on its home struct. The cs twin: same fields, same encoding — C# has real 64-bit shifts, so `slot | brand << 24 | gen << 32` carries over bitwise where JS had to re-pack by multiplication. `__koru_row_of` answers -1 for absent (rows are >= 0) — the js `null`/zig `?usize` sentinel — and `__koru_resolve` throws what zig panics. Members are statics of the cell's `static class`, so bodies here read them bare.

~part hostemit koru_std/store.hostemit.kz

Koru Standard Library: the `hostemit` part of store.kz. Joined via `~part hostemit` in store.kz; merged into the module at load. Host-source emit bodies lifted out of their topical parts as the third backend's arms grew them past the line wall. Each fn is reached through a member on its home struct (or a bare call, for cellRead, which was already module-scope in cols). A `stored` write to the indexed column: `write` is the cell write (`cell[row] = <value>`) and `value` its rhs expression. When the value actually changes the row LEAVES its old bucket (membership is eager — a stale member under the old key would answer for a row that stopped carrying it) and JOINS the new one at the end — a write that moves membership is a join for ordering purposes. `__koru_iold` is captured before the write.

~part bulkdetect koru_std/store.bulkdetect.kz

Koru Standard Library: the `bulkdetect` part of store.kz. Joined via `~part bulkdetect` in store.kz; merged into the module at load. Does any leaf column carry a std/refine met (bounds or clamp)? The same fold the emit prelude runs — refine's own metFields — so gate and guard cannot disagree about what a facet says.

~part ixrefs koru_std/store.ixrefs.kz

Koru Standard Library: the `ixrefs` part of store.kz. Joined via `~part ixrefs` in store.kz; merged into the module at load. `store[index].field` → the SoA column read, for ONE store, in arbitrary text. The index is itself an expression and may hold another indexed read (`cells[cells[h].next].v`, one hop along an intrusive chain). The outer match consumes the whole span, so the inner one is lowered by an explicit recursive descent over the same scope (690_245).

~part prewrite koru_std/store.prewrite.kz

Koru Standard Library: the `prewrite` part of store.kz. Joined via `~part prewrite` in store.kz; merged into the module at load.

~part srefscan koru_std/store.srefscan.kz

Koru Standard Library: the `srefscan` part of store.kz. Joined via `~part srefscan` in store.kz; merged into the module at load.

~part iprov koru_std/store.iprov.kz

Koru Standard Library: the `iprov` part of store.kz. Joined via `~part iprov` in store.kz; merged into the store module at load. STORE.IPROV — `store[base.field]` index provenance (690_365) A subscript's index used to reach `__koru_resolve` unchecked: the runtime brand test panicked on whatever it found (a scalar `0` carries brand 0, which is deliberately not a store brand). One spelling the compiler CAN see through: `base.field` where `base` names a declared store lowers to a read of the cell itself — `storeRefsAll` rewrites it to `__koru_store_<base>.<field>` unconditionally — so its provenance is decidable here rather than inside a panic. Three verdicts. A PLURAL `base` makes `base.field` the whole column — an array, never a handle. A capacity-1 `base` puts it on the cell's write history: if every write the scan can see is provably scalar the cell never holds a handle and the subscript is refused; one write that could carry a handle — a `| row` binding, another cell read, any name the scan cannot classify — keeps it legal (the sanctioned handle-carrying column, `ui.sel` of 690_075). Anything else is OPAQUE and the runtime check stands: a bound name shadowing the store, a base that is no store, a member that is no column, a seed or write the scan cannot read. The documented handle sources stay legal because they never land here: `| row` bindings and cursors are site-bound names (opaque), and a handle-carrying column of the TARGET store is claimed by the field-of- store self-FK arm before this scan runs (690_048).

~part qtail koru_std/store.qtail.kz

Koru Standard Library: the `qtail` part of store.kz — the query site's continuation-tail plumbing: the named-arms/branchless-sequel split, the sweep-run unit's capture re-threading, and the unit's assembly. Joined via `~part qtail` in store.kz; merged into the store module at load.

~part qguard koru_std/store.qguard.kz

Koru Standard Library: the `qguard` part of store.kz. Joined via `~part qguard` in store.kz; merged into the module at load.

~part qsites koru_std/store.qsites.kz

Koru Standard Library: the `qsites` part of store — joined via `~part qsites` in store.kz; members land in koru_store. The scans that find a store's sites. `flatItems`/`collectFlat` are the program-items flatten every store scan builds on (memoized per items-epoch — see the contract below); they see top-level items and module trees, never continuation trees. `nestedQSites` is the continuation-tree half: a `std/store:preorder(s)` spelled inside an arm body is a CONTINUATION whose node is the invocation — never a top-level `.flow` item, so the flat scan cannot see it. The transform runner hands that nested site to its transform inside a synthetic flow view (transform_pass_runner.siteView) keyed on the holding continuation's own location — and it is that view's `__store_qsweep_<s>_L<line>` the site transform then looks up. This part mints the same view on the coordinator side so the qrow/qbody/qsweep units exist for it to find. Every item in the program, flattened through `.module_decl`, in tree order, as POINTERS into the program's own arrays. `program.items` is one level deep: an imported module arrives as a single `.module_decl` carrying its own items. Every scan in this file that reads `program.items` directly is therefore blind to a store declared, watched, queried or written inside a library — and the failure is not a miss, it is a diagnostic pointing at the author: "unknown store — no std/store:new(c) found", with the `new` sitting four lines above the `watch`. Returns items not flows for the `findSynthDecl` reason: safe for a predicate naming what only the store machinery mints (`__store_*`, `std/store:<verb>`), UNSAFE for a general `.flow` scan. Every caller is predicate-guarded; a new one must be too. Pointers, not copies — a site may keep `&pi.flow` and the mutating walks can `@constCast` a real program node rather than a temporary. The result is MEMOIZED per items-epoch. Flattening is O(program); the store machinery calls it per field, per leaf, per interceptor arm — thousands of times per compile — and every result lands on the compile arena, which frees nothing until exit. That product is what SIGKILLed monolithic programs (≈9.7 GB live for the 003_ecs benchmark). The memo keeps ONE flatten per items-epoch. The key is the items SLICE HEADER (buffer pointer + length): every structural write-back — appendItems, boxed replacements, site splices — allocates a fresh top-level array, so minted declarations are never hidden behind a stale list, and a write path that mutated the header in place would serve stale structure (none exists; this is the memo's contract). Content mutations (rewrites that @constCast nodes in place) are visible through the cached pointers and need no invalidation. Returned slices are never freed or mutated, only abandoned, so a nested call that evicts the cache cannot invalidate an outer caller's iteration.

~part qcols koru_std/store.qcols.kz

Koru Standard Library: the `qcols` part of store — joined via `~part qcols` in store.kz; members land in koru_store. The `! query`/`! first` column set for a non-view store. The insert event's input shape is the INSERT surface: user columns plus the trailing synthetic `__site_line`. A [tree] store's synthesized `parent` is absent from it by ruling (TT1 — inserts never name `parent`), but TT0 keeps the column QUERYABLE (`query … entity.parent` so traversal can follow it), so the row binding's column list is the insert surface plus `parent` when the store is a tree. (`kind` needs no such patch: a kinded store's inserts name it, so it is already on the surface.)

~part lowertext koru_std/store.lowertext.kz

Koru Standard Library: the `lowertext` part of store.kz. Joined via `~part lowertext` in store.kz; merged into the module at load. The shared text-lowering surface: `storeLowerText` composes the cell and indexed passes for one text slot, and `storeNameIn`/`isPrecededByIs` are the small predicates the rewrites share — a name-list membership test and the `is`/`not is` lookahead that keeps a bare identity-store read out of `x is name` comparisons.

~part igate koru_std/store.igate.kz

The `igate` part — declaration gates on the `new` site: the ONE-`new`-PER- NAME rule and the std/indexes dead-claim enumeration. Split out of store.new.kz (line-pinned): `new`'s transform calls each gate once per site and stays under its pin; the enumeration machinery lives here. Both gates guard the same family as the second-index-decl wall (690_328): a declaration the program cannot serve is refused at its own location, loudly, before it can mint broken Zig or be blamed on a downstream consumer.