Problem. nexum:host/local-store forces a guest to copy a full payload across the wasm boundary to answer questions that do not need the payload. Existence checks and size/count queries pull the whole value (or the whole key set) just to discard it.
Current. The interface is get / set / delete / list-keys. To test existence a guest calls get(key) and inspects is_some(), marshalling the entire value; to size a value it must fetch it; to count keys under a prefix it calls list-keys(prefix) and takes .len(), materialising every matching key string.
Proposed. Add three metadata queries to the interface, all sharing one theme: answer a question about the store without transferring the bytes.
contains: func(key: string) -> result<bool, fault> - existence without fetching the value.
len: func(key: string) -> result<option<u64>, fault> - value byte length, none if the key is absent, without fetching the value.
count: func(prefix: string) -> result<u64, fault> - number of keys under a prefix without materialising the key list.
The SDK LocalStoreHost trait gains matching methods with default bodies (contains via get(..).is_some(), len via get(..).map(|v| v.len() as u64), count via list_keys(..).len()), so a backend opts into the cheap path only when it can beat the default; impls that do not override still compile.
Scope / files. wit/nexum-host/local-store.wit (the three funcs); crates/nexum-runtime/src/host/impls/local_store.rs (real backend impls; redb can range-count and stat cheaply); crates/nexum-sdk/src/host.rs (trait + defaults); crates/nexum-sdk/src/wit_bindgen_macro.rs (conversion routing); the two mock crates nexum-sdk-test and shepherd-sdk-test; rebuild the module wasms in-tree, same footprint as the generic-interfaces migration.
Risk / needs-design. count and len are not guaranteed O(1): on a keystore-style backend count is a prefix scan and len may still read the record, so the doc comments must say "may be a scan" rather than implying a cheap counter. Open scoping question: ship all three, or land contains alone (clear win) and defer len / count until a consumer needs them. Naming: len (value bytes) versus count (key cardinality) are deliberately different words for different axes; confirm before freezing.
Timing. This is an ABI addition to a host interface (nexum:host), not the Swarm p2p wire, so there is no SwarmHardfork gate, but it must land before the M7 vocabulary freeze; adding host-interface funcs after the freeze defeats its purpose. Milestoned M5 on that basis; re-slot if the KV metadata surface is considered part of a later backend pass instead.
Relates. #206 / #208 established local-store's current fault-typed shape. Sibling backend-enhancement issue nullislabs/nexum-runtime#37.
Problem.
nexum:host/local-storeforces a guest to copy a full payload across the wasm boundary to answer questions that do not need the payload. Existence checks and size/count queries pull the whole value (or the whole key set) just to discard it.Current. The interface is
get/set/delete/list-keys. To test existence a guest callsget(key)and inspectsis_some(), marshalling the entire value; to size a value it must fetch it; to count keys under a prefix it callslist-keys(prefix)and takes.len(), materialising every matching key string.Proposed. Add three metadata queries to the interface, all sharing one theme: answer a question about the store without transferring the bytes.
contains: func(key: string) -> result<bool, fault>- existence without fetching the value.len: func(key: string) -> result<option<u64>, fault>- value byte length,noneif the key is absent, without fetching the value.count: func(prefix: string) -> result<u64, fault>- number of keys under a prefix without materialising the key list.The SDK
LocalStoreHosttrait gains matching methods with default bodies (containsviaget(..).is_some(),lenviaget(..).map(|v| v.len() as u64),countvialist_keys(..).len()), so a backend opts into the cheap path only when it can beat the default; impls that do not override still compile.Scope / files.
wit/nexum-host/local-store.wit(the three funcs);crates/nexum-runtime/src/host/impls/local_store.rs(real backend impls; redb can range-count and stat cheaply);crates/nexum-sdk/src/host.rs(trait + defaults);crates/nexum-sdk/src/wit_bindgen_macro.rs(conversion routing); the two mock cratesnexum-sdk-testandshepherd-sdk-test; rebuild the module wasms in-tree, same footprint as the generic-interfaces migration.Risk / needs-design.
countandlenare not guaranteed O(1): on a keystore-style backendcountis a prefix scan andlenmay still read the record, so the doc comments must say "may be a scan" rather than implying a cheap counter. Open scoping question: ship all three, or landcontainsalone (clear win) and deferlen/countuntil a consumer needs them. Naming:len(value bytes) versuscount(key cardinality) are deliberately different words for different axes; confirm before freezing.Timing. This is an ABI addition to a host interface (
nexum:host), not the Swarm p2p wire, so there is noSwarmHardforkgate, but it must land before the M7 vocabulary freeze; adding host-interface funcs after the freeze defeats its purpose. Milestoned M5 on that basis; re-slot if the KV metadata surface is considered part of a later backend pass instead.Relates. #206 / #208 established local-store's current fault-typed shape. Sibling backend-enhancement issue nullislabs/nexum-runtime#37.