store

A content-addressed object store with URL-dispatched backends. A single API surface operates against multiple storage backends (local filesystem, in-memory, HTTP, S3-compatible, WebDAV, FTP/FTPS/SFTP, and a CSRP service tier), selected at open time by the URL scheme. Doc IDs are the SHA-256 of a document's strict canonical bytes, so identity is identical across bindings, backends, compression states, and wire encodings — enabling lossless migration and free dedup. A mutable alias layer maps names to hashes on top of the immutable content.

store:open

[$store:open] -> element — Open a Store against a backend chosen by the URL scheme, with default options.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [$store:get-doc $s $h]]
          
            [doc [item 'hello']]
          

store:open-opts

[$store:open-opts] -> element — Open a Store with explicit options for compression, encoding, sharding, auth, caching, and read-only.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open-opts "mem://" [map read-only="true"]]] [$store:put-doc $s [doc [item "x"]]]]
          
            cx-err:CXER1110
          

store:put-doc

[$store:put-doc] -> string — Store a document and return its SHA-256 content hash; identical content stores once.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [$store:get-doc $s $h]]
          
            [doc [item 'hello']]
          

store:put-doc-stream

[$store:put-doc-stream] -> string — Store a document from a readable byte-source in bounded chunks, never holding it fully resident.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $a [$store:put-doc $s [user name=al]]] [= $b [$store:put-doc-stream $s [user name=al]]] [= $a $b]]
          
            true
          

store:get-doc

[$store:get-doc] -> any — Retrieve the document for a hash, re-validating integrity after decode.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [$store:get-doc $s $h]]
          
            [doc [item 'hello']]
          

store:put-doc-text

[$store:put-doc-text] -> string — Store a document given as canonical/parseable TEXT (vs put-doc's node); canonicalizes so the hash and dedup match put-doc of the same doc. The text-body half of the CSRP server path.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $a [$store:put-doc-text $s "[doc [v 1]]"]] [$count [$store:list-docs $s]]]
          
            1
          

store:get-doc-text

[$store:get-doc-text] -> [or string [sequence string]] — Return the stored canonical TEXT for a hash (vs get-doc's node), or absence (empty) on a miss — never null, never an err. The text-body half of the CSRP server path.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [$count [$store:get-doc-text $s "0000000000000000000000000000000000000000000000000000000000000000"]]]
          
            0
          

store:csrp-handle

[$store:csrp-handle] -> any — CSRP reference-server per-request handler: read one request off an http exchange, route it to the local embedded store, write the cxd-text response. The accept loop stays a CX program; this does one request/response cycle. net-gated.

            [?lib 'cx-stdlib/store']
[$store:csrp-handle [exchange state=open url='tcp://0.0.0.0:8080'] [$store:open "mem://"]]
          
            cx-err:CXER0271
          

store:list-docs

[$store:list-docs] -> [sequence string] — Return the hashes of every document stored in the Store.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h1 [$store:put-doc $s [doc [item "hello"]]]] [= $h2 [$store:put-doc $s [doc [item "hello"]]]] [$store:list-docs $s]]
          
            ('01699895b66541c3d480d15af00e3ef54bbc723378919018101dc57bed4b00f9')
          

store:iter-docs

[$store:iter-docs] -> [sequence element] — Lazily yield hash-and-document pairs, keeping memory bounded regardless of corpus size.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [$store:iter-docs $s]]
          
            ([entry hash='01699895b66541c3d480d15af00e3ef54bbc723378919018101dc57bed4b00f9' [doc [item 'hello']]])
          

store:query

[$store:query] -> [sequence element] — Evaluate a CXPath against every document, returning the matches per doc.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [root [user name=al]]]] [$count [$store:query $s "//user"]]]
          
            1
          

store:modify-doc

[$store:modify-doc] -> string — Apply a [?modify] action (set-attr, remove, append, rename, [using FN], ... with optional select=) to the doc at a hash and store the result as a new doc, returning its hash; [using FN] runs the lambda client-side per selected node.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [= $h2 [$store:modify-doc $s $h [set-attr name=v value="x"]]] [= $h $h2]]
          
            false
          

store:put-def

[$store:put-def] -> string — Store CX code (a [?def] source) by its Tier-2 code identity and return the hash; alpha-equivalent definitions store once.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [$eq [$store:get-def $s [$store:put-def $s '[?def f ($x) $x]']] '[?def f ($x) $x]']]
          
            true
          

store:get-def

[$store:get-def] -> [or string [sequence string]] — Return the stored CX code source for a Tier-2 code hash, or absence (empty) on a miss.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h1 [$store:put-def $s '[?def f ($x) $x]']] [= $h2 [$store:put-def $s '[?def f ($y) $y]']] [$eq $h1 $h2]]
          
            true
          

store:delete-doc

[$store:delete-doc] -> bool — Delete the doc at a hash, returning whether it was present.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open-opts "mem://" [map read-only="true"]]] [$store:delete-doc $s "deadbeef"]]
          
            cx-err:CXER1110
          

store:exists

[$store:exists] -> bool — Report whether a doc with the given hash is present — a cheap existence check.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [$store:exists $s $h]]
          
            true
          

store:capabilities

[$store:capabilities] -> map — Report the Store's read/write/list traits plus its backend, URL, compression, and encoding.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [$store:capabilities $s]]
          
            [map read=true write=true list=true backend=mem url='mem://' compression=none encoding=cxbin]
          

store:close

[$store:close] -> null — Close the Store; subsequent operations on it raise CXER1130.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $c [$store:close $s]] [$store:list-docs $s]]
          
            cx-err:CXER1130
          

store:set-alias

[$store:set-alias] -> null — Bind a name to an existing doc hash in the mutable alias layer (last-write-wins).

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [= $a [$store:set-alias $s "latest" $h]] [$store:get-alias $s "latest"]]
          
            '01699895b66541c3d480d15af00e3ef54bbc723378919018101dc57bed4b00f9'
          

store:get-alias

[$store:get-alias] -> [or string [sequence string]] — Resolve an alias name to its hash, or absence (empty) if it does not resolve.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [= $a [$store:set-alias $s "latest" $h]] [$store:get-alias $s "latest"]]
          
            '01699895b66541c3d480d15af00e3ef54bbc723378919018101dc57bed4b00f9'
          

store:list-aliases

[$store:list-aliases] -> [sequence element] — Return every name-to-hash alias binding in the Store.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [= $a [$store:set-alias $s "latest" $h]] [$store:list-aliases $s]]
          
            ([alias name=latest hash='01699895b66541c3d480d15af00e3ef54bbc723378919018101dc57bed4b00f9'])
          

store:delete-alias

[$store:delete-alias] -> bool — Remove an alias, returning whether it existed; the underlying doc is untouched.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [= $a [$store:set-alias $s "latest" $h]] [$store:delete-alias $s "latest"]]
          
            true
          

store:migrate

[$store:migrate] -> element — Copy every doc and alias from one Store to another, losslessly across backends and encodings.

            [?lib 'cx-stdlib/store']
[?let [= $a [$store:open "mem://"]] [= $h [$store:put-doc $a [doc [item "hello"]]]] [= $b [$store:open "mem://"]] [$store:migrate $a $b]]
          
            [migration-report doc-count=1 hashes-verified=1 bytes-written=20]
          

store:clone

[$store:clone] -> element — Copy every reachable object and doc-ref from a source Store into an EMPTY destination (errors if the destination already holds docs); transfers only objects the destination is missing — the object-identity clone over the wire.

            [?lib 'cx-stdlib/store']
[?let [= $a [$store:open "mem://"]] [= $h [$store:put-doc $a [doc [item "hello"]]]] [= $b [$store:open "mem://"]] [= $r [$store:clone $a $b]] [$store:get-doc $b $h]]
          
            [doc [item 'hello']]
          

store:push

[$store:push] -> element — Send the local Store's objects the remote is missing, then advance the remote's refs (have->put-missing->set-ref); content-addressed and idempotent. Works embedded<->embedded and embedded<->daemon.

            [?lib 'cx-stdlib/store']
[?let [= $l [$store:open "mem://"]] [= $h [$store:put-doc $l [doc [v 1]]]] [= $rm [$store:open "mem://"]] [= $r [$store:push $l $rm]] [$store:get-doc $rm $h]]
          
            [doc [v 1]]
          

store:pull

[$store:pull] -> element — Bring the remote's objects the local Store is missing, plus its refs, into the local Store (refs->have->get-missing). For a content-addressed store pull and fetch coincide (no working tree, immutable doc-refs).

            [?lib 'cx-stdlib/store']
[?let [= $rm [$store:open "mem://"]] [= $h [$store:put-doc $rm [doc [v 2]]]] [= $l [$store:open "mem://"]] [= $r [$store:pull $l $rm]] [$store:get-doc $l $h]]
          
            [doc [v 2]]
          

store:fetch

[$store:fetch] -> element — Bring the remote's objects and refs into the local Store without merging (see pull on the pull/fetch equivalence for a content-addressed store).

            [?lib 'cx-stdlib/store']
[?let [= $rm [$store:open "mem://"]] [= $h [$store:put-doc $rm [doc [v 3]]]] [= $l [$store:open "mem://"]] [= $r [$store:fetch $l $rm]] [$store:get-doc $l $h]]
          
            [doc [v 3]]
          

store:status

[$store:status] -> element — A snapshot of the Store's heads + object economy: docs (heads), distinct objects, the logical/distinct dedup ratio, and unflushed refs (a remote mount reports the head count only — object economy lives server-side).

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [v 1]]]] [$store:status $s]]
          
            [status backend=mem docs=1 objects=5 logical=5 distinct=5 unflushed=1]
          

store:mounts

[$store:mounts] -> element — Enumerate the stores a store-serve daemon serves — name, backend, capability flags — tenant-filtered, with admin RBAC enforced server-side (CSRP daemon-level op). Inherently service-tier: it needs a cx-store:// handle, and on a local handle it raises CXER1709 (a local handle IS its only store; there is no daemon to enumerate).

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [$store:mounts $s]]
          
            cx-err:CXER1709
          

store:config-reload

[$store:config-reload] -> element — Trigger a store-serve daemon's runtime config reload: the daemon re-reads its OWN config source (nothing rides the wire) and answers [config-reload applied=... generation=... changed=...], or refuses with CXER1711/CXER1712 verbatim; admin RBAC enforced server-side. Daemon-level like mounts — a local handle raises CXER1709 (there is no daemon config to reload).

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [$store:config-reload $s]]
          
            cx-err:CXER1709
          

store:verify

[$store:verify] -> element — Whole-graph integrity pass: every live doc must reconstruct from the object graph, or it raises CXER1120 naming the first offending store-key. This is the check that used to run inline on EVERY open of an object-graph store; under demand-paged loading it runs on demand (or from a background task) instead, while per-object integrity is unchanged — every paged read self-verifies its hash, so corruption refuses loudly at first touch. Refuses on the flat document model, whose per-read hash check IS its verification.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "x"]]]] [$store:verify $s]]
          
            [verification valid=true docs=1 objects=5]
          

store:log

[$store:log] -> [sequence element] — The ref-log: each held doc-ref is one epoch in insertion order (store-key -> doc-root). Old roots persist as objects, so this is the Store's linear history without a separate commit DAG.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [v 1]]]] [$count [$store:log $s]]]
          
            1
          

store:gc

[$store:gc] -> element — Reclaim objects no live doc-ref reaches AND make the result durable (per-substrate compaction); gc = prune + flush. A content-addressed object stays live while ANY ref reaches it, so a shared subtree survives another doc's delete.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $a [$store:put-doc $s [doc [item "x"]]]] [= $b [$store:put-doc $s [doc [item "y"]]]] [= $d [$store:delete-doc $s $a]] [$store:gc $s]]
          
            [gc-result reclaimed=4 objects=5]
          

store:prune

[$store:prune] -> element — Reclaim objects no live doc-ref reaches (the subset of gc that drops unreachable objects without rewriting durable storage).

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $a [$store:put-doc $s [doc [item "x"]]]] [= $b [$store:put-doc $s [doc [item "y"]]]] [= $d [$store:delete-doc $s $a]] [$store:prune $s]]
          
            [prune-result reclaimed=4 objects=5]
          

store:rotate-kek

[$store:rotate-kek] -> element — Re-wrap every at-rest envelope's data key from its recorded KEK to a new tenant key (KEK rotation, store.md §9.1): payloads and content addresses untouched, atomic per object, resumable (already-current envelopes skip), fail-closed (an envelope unwrapping under neither key aborts CXER1142). Only meaningful on an encrypted store — a plaintext store raises CXER1141.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [$store:rotate-kek $s "tenant-b"]]
          
            cx-err:CXER1141
          

store:diff

[$store:diff] -> element — The structural diff of two stored docs BY HASH: identical subtrees share a hash and are skipped in O(1), so the cost is O(changed), not O(size). Returns [diff [change path=... kind=modified|added|removed] ...]; an empty [diff] means identical. Read-only (the plumbing a future structural merge builds on).

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $a [$store:put-doc $s [order [id 1] [amt 100]]]] [= $b [$store:put-doc $s [order [id 1] [amt 200]]]] [$store:diff $s $a $b]]
          
            [diff [change path='/order/amt/[0]' kind=modified]]
          

store:branch

[$store:branch] -> element — Point a mutable named ref at a doc (branches/tags ARE git refs over the alias layer). Refuses to MOVE an existing branch that points elsewhere (CXER1114, the CAS-safe non-fast-forward reject); creating a new branch or re-pointing to its current target succeeds.

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [v 1]]]] [= $br [$store:branch $s "main" $h]] [= [$store:get-alias $s "main"] $h]]
          
            true
          

store:branch-force

[$store:branch-force] -> element — Move a named ref to a target UNCONDITIONALLY (the --force that skips the CAS check branch enforces).

            [?lib 'cx-stdlib/store']
[?let [= $s [$store:open "mem://"]] [= $h1 [$store:put-doc $s [doc [v 1]]]] [= $h2 [$store:put-doc $s [doc [v 2]]]] [= $b1 [$store:branch $s "main" $h1]] [= $b2 [$store:branch-force $s "main" $h2]] [= [$store:get-alias $s "main"] $h2]]
          
            true