OverviewFilesCommitsIssuesDocsReleasesPeers

atomspace-gpu commits / a318949

M1: Hypercore-backed op-log — durable replay (#1) + fork (#2)
Swaps the M0 in-memory array for a real Hypercore and proves two of Nakajima's three ActiveGraph properties over an append-only log. run.sh drives three phases, all green: - [full] live append + replay round-trip on the Hypercore (src 8==dst 8) - [verify] GOLD #1 durable deterministic replay: the daemon is RESTARTED on the same Hypercore dir and rebuilds a byte-identical AtomSpace (persistence across process lifetimes). - [fork] GOLD #2 cheap fork: `loadat K` is a read-only checkout at seq K (get(0..K)) -> an earlier, strictly-smaller graph, no reprocessing (full=8, checkout@3=3, subset, strict). daemon.js: op-log = Hypercore (append/get/truncate); ordered promise chain so load/barrier observe all prior stores; usage now `bare daemon.js <sock> <storage-dir>`. New `loadat <K>` verb. m0_roundtrip.cc: modes full/verify/fork; creation-order store so any prefix is a self-consistent sub-graph. Deferred: Values, the guile-loadable HyperStorageNode : StorageNode (packaging only), Autobase multi-writer (M4). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
a31894996002d6b5d00ce8ab30df9ff97946cf85
by plankatron <fleeky@gmail.com> · 2026-07-05T14:37:45.000Z

Changed files (6) +803 -172

experiments/m0-uds-bridge/README.md +52 -39
……@@ -1,57 +1,70 @@
1# M0 — UDS bridge + codec round-trip
1# hyper-atomspace bridge — M0 + M1
22
3First milestone of the HyperStorageNode (spec: `../../spec/hyperstoragenode.md`;
4`atomspace` org issue #4). Proves the data path with **no Hypercore** and **no full
5StorageNode/guile-module boilerplate** yet:
3Milestones of the HyperStorageNode (spec: `../../spec/hyperstoragenode.md`;
4`atomspace` org issue #4). A Bare daemon holds the op-log; a C++ client speaks the
5real opencog s-expr codec over a UNIX-domain socket. An AtomSpace is a
6**deterministic projection of an append-only log** — and here the log is a
7**Hypercore**.
68
79```
8 C++ (real Sexpr codec) Bare daemon (in-memory s-expr log)
9 ──────────────────────── ─────────────────────────────────
10 build small AtomSpace
11 Sexpr::encode_atom ──store──▶ log.push(sexpr)
12 (barrier) ──barrier─▶ ok
13 (replay) ──load────▶ (sexpr1 sexpr2 …)
14 Sexpr::decode_atom ◀───────────
15 gold check: src AtomSpace ≡ dst AtomSpace → M0 GOLD PASS
10 C++ (real Sexpr codec) Bare daemon (Hypercore op-log)
11 ──────────────────────── ──────────────────────────────
12 build AtomSpace
13 Sexpr::encode_atom ──store───▶ core.append(sexpr)
14 (barrier) ──barrier──▶ ok
15 (replay) ──load─────▶ ( get(0..len) )
16 (checkout @K) ──loadat K─▶ ( get(0..K) ) ← cheap fork
17 Sexpr::decode_atom ◀────────────
18 gold check: src AtomSpace ≡ dst AtomSpace
1619```
1720
18## What this establishes
19- A C++ `AF_UNIX` client (`HyperChannel`, adapted from `CogSimpleStorage`'s
20 `do_send`/`do_recv`, TCP→UDS) round-trips atoms through a **Bare** daemon.
21- The wire payload is the **real opencog s-expr codec** (`Sexpr::encode_atom` /
22 `Sexpr::decode_atom` from `libsexpr`), not a bespoke serialization — so encode is
23 a genuine inverse of decode.
24- bare-net UDS framing + half-open handling (`allowHalfOpen:false` + destroy on
25 `end`, the hyper-svc leak fix) work against a foreign (C++) client.
21## Milestones proven here (`./run.sh` runs all three)
22- **M0 — bridge + codec round-trip.** C++ `AF_UNIX` client round-trips atoms
23 through the Bare daemon; payload is the real `libsexpr` codec (encode is a
24 genuine inverse of decode). `[full]` phase.
25- **M1 #1 — durable deterministic replay.** The daemon is **restarted on the same
26 Hypercore dir**; replaying the log rebuilds a byte-identical AtomSpace. `[verify]`
27 phase → `GOLD #1`.
28- **M1 #2 — cheap fork.** `loadat K` is a read-only **checkout at seq K**: read
29 fewer blocks, get an earlier, strictly-smaller graph, no reprocessing. `[fork]`
30 phase → `GOLD #2` (full=8, checkout@3=3, subset ✓, strict ✓).
2631
2732## Files
2833| File | Role |
2934|---|---|
30| `daemon.js` | Bare UDS server; in-memory `log[]` of s-expr strings; verbs `store`/`load`/`clear`/`barrier`/`count`. At M1 the array becomes a Hypercore. |
31| `m0_roundtrip.cc` | C++ harness. `HyperChannel` = the reusable transport the future `HyperStorageNode` embeds; `main()` builds an 8-atom AtomSpace, stores, replays, gold-checks. |
32| `run.sh` | build + start daemon + run harness + gold check + cleanup. |
35| `daemon.js` | Bare daemon. Op-log = a **Hypercore** (`append` on store, `get(0..len)` on load, `get(0..K)` on `loadat`, `truncate(0)` on clear). Ordered promise-chain so load/barrier observe all prior stores. `allowHalfOpen:false` + destroy-on-`end` (hyper-svc leak fix). `usage: bare daemon.js <sock> <storage-dir>`. |
36| `m0_roundtrip.cc` | C++ harness. `HyperChannel` = reusable `AF_UNIX` transport (from `CogSimpleStorage` do_send/do_recv) that lifts into `HyperStorageNode : public StorageNode`. Modes `full` / `verify` / `fork`. |
37| `run.sh` | build + 3-phase drive (full → restart-verify → fork) + cleanup. |
3338
3439## Run
3540```bash
36./run.sh # prints "M0 GOLD PASS", exits 0
41./run.sh
42# [full] live round-trip src=8 dst=8 PASS
43# [verify] durable replay src=8 dst=8 GOLD #1 PASS
44# [fork] full=8 checkout@3=3 subset=1 strict=1 GOLD #2 PASS
45# M1 ALL PASS
3746```
38Requires: `bare` (v1.26+), `g++` (C++20), opencog installed under `/usr/local`
39(`libatomspace`, `libsexpr`, `libatombase`, `libatom_types`). `npm install` pulls
40`bare-net`/`bare-fs`/`bare-process` into a local `node_modules` (gitignored).
47Requires: `bare` (v1.26+), `g++` (**C++20** — opencog headers use `std::atomic::wait`),
48opencog under `/usr/local` (`libatomspace`/`libsexpr`/`libatombase`/`libatom_types`).
49`npm install` pulls `bare-net`/`bare-fs`/`bare-process`/`hypercore` into a local
50`node_modules` (gitignored).
4151
4252## Wire protocol (newline-framed)
4353| Request | Reply | Meaning |
4454|---|---|---|
45| `store <sexpr>` | — | append one atom's s-expr to the log (fire-and-forget) |
46| `load` | `(<sexpr>…)\n` | whole log wrapped in one outer paren (the shape the C++ decode loop expects) |
47| `clear` | `ok\n` | empty the log |
48| `barrier` | `ok\n` | sync point (ordered stream ⇒ all prior stores are applied) |
49| `count` | `<n>\n` | log length (debug) |
55| `store <sexpr>` | — | `core.append(sexpr)` (fire-and-forget) |
56| `load` | `(<sexpr>…)\n` | replay whole log |
57| `loadat <K>` | `(<sexpr>…)\n` | replay prefix 0..K (checkout / cheap fork) |
58| `clear` | `ok\n` | `core.truncate(0)` |
59| `barrier` | `ok\n` | sync point (all prior stores applied) |
60| `count` | `<len>\n` | `core.length` |
5061
51## Deliberately NOT here (deferred)
52- **Hypercore** — the log is a plain array (that is M1: append + replay + fork).
53- **Values** — structure only; per the synthesis rule *event-source the graph,
54 checkpoint the Values* (`../../spec/activegraph-synthesis.md`).
55- **Full `HyperStorageNode : public StorageNode` + guile module** — `HyperChannel`
56 is written to lift straight into it at M1; no atom_types/PersistSCM/CMake yet.
57- **Autobase multi-writer** — single client, single daemon (M4).
62## Deferred (next)
63- **Values** — structure only; per *event-source the graph, checkpoint the Values*
64 (`../../spec/activegraph-synthesis.md`).
65- **`HyperStorageNode : public StorageNode` + guile module** — packaging, not new
66 capability: the data path is proven and `HyperChannel` is the transplant unit.
67 Needs atom_types codegen + PersistSCM + CMake (a loadable `.so`).
68- **Autobase multi-writer** (M4) — two daemons, one linearized log = two agents.
69- **Branch-fork with divergent writes** — M1 `loadat` is a read-only checkout;
70 true forking-with-writes rides Autobase.
experiments/m0-uds-bridge/daemon.js +47 -33
……@@ -1,41 +1,51 @@
1// M0 hyper-atomspace daemon (Bare).
1// hyper-atomspace daemon (Bare) — M1: Hypercore-backed op-log.
22//
3// Purpose: prove the HyperStorageNode bridge + s-expr codec round-trip with an
4// in-memory op-log. NO Hypercore yet (that is M1). The daemon holds an array of
5// s-expr strings (one per stored atom) and can replay them on demand.
3// The op-log is a real Hypercore (append-only, durable on disk). store appends
4// one s-expr per atom; load replays the whole log; loadat replays a prefix (a
5// read-only checkout at seq K = "cheap fork": read fewer blocks, get an earlier
6// graph, no reprocessing). This is the M1 backend swap from M0's in-memory array.
7//
8// usage: bare daemon.js <socket-path> <storage-dir>
69//
710// Wire protocol — newline-framed request lines over a UNIX-domain socket:
8// store <sexpr>\n append <sexpr> to the log. NO reply (fire-and-forget,
9// mirrors CogSimpleStorage::storeAtom).
10// load\n reply one line: (<sexpr1><sexpr2>...)\n — the whole log
11// wrapped in a single outer paren, the exact shape the C++
12// side's decode loop (cf. CogSimpleStorage::decode_atom_list)
13// expects.
14// clear\n empty the log. reply: ok\n
11// store <sexpr>\n append <sexpr> to the log. NO reply (fire-and-forget).
12// load\n reply: (<sexpr0>…<sexpr_{len-1}>)\n — whole log.
13// loadat <K>\n reply: (<sexpr0>…<sexpr_{K-1}>)\n — prefix/checkout @K.
14// clear\n truncate the log to 0. reply: ok\n
1515// barrier\n sync point. reply: ok\n
16// count\n reply: <n>\n (debug)
16// count\n reply: <len>\n
1717//
18// Framing note: bare-net defaults allowHalfOpen:true and only emits 'close' on an
19// explicit destroy (see hyper-svc UDS leak post-mortem). We create the server
20// allowHalfOpen:false AND destroy on 'end' so client fds are released.
18// All commands run on a single ordered promise-chain, so by the time a load or
19// barrier executes, every prior store's append has resolved.
2120
2221import net from 'bare-net'
2322import fs from 'bare-fs'
2423import process from 'bare-process'
24import Hypercore from 'hypercore'
2525
2626const sockPath = process.argv[2]
27if (!sockPath) {
28 console.error('usage: bare daemon.js <socket-path>')
27const storageDir = process.argv[3]
28if (!sockPath || !storageDir) {
29 console.error('usage: bare daemon.js <socket-path> <storage-dir>')
2930 process.exit(1)
3031}
3132
32// Fresh bind: a stale socket file makes listen() fail with EADDRINUSE.
33// Fresh socket bind: a stale socket file makes listen() fail.
3334try { fs.unlinkSync(sockPath) } catch (_) { /* not there — fine */ }
3435
35/** @type {string[]} the in-memory op-log: one s-expr per stored atom. */
36const log = []
36const core = new Hypercore(storageDir, { valueEncoding: 'utf-8' })
37await core.ready()
38
39// Read blocks [0, upto) and wrap them in one outer paren — the exact shape the
40// C++ decode loop expects.
41async function replay (upto) {
42 const n = Math.max(0, Math.min(upto, core.length))
43 let body = ''
44 for (let i = 0; i < n; i++) body += await core.get(i)
45 return '(' + body + ')\n'
46}
3747
38function handleLine (line, sock) {
48async function handleLine (line, sock) {
3949 if (line.length === 0) return
4050 const sp = line.indexOf(' ')
4151 const verb = sp === -1 ? line : line.slice(0, sp)
……@@ -43,20 +53,23 @@ function handleLine (line, sock) {
4353
4454 switch (verb) {
4555 case 'store':
46 log.push(rest)
56 await core.append(rest)
4757 return // no reply
4858 case 'load':
49 sock.write('(' + log.join('') + ')\n')
59 sock.write(await replay(core.length))
60 return
61 case 'loadat':
62 sock.write(await replay(parseInt(rest, 10) || 0))
5063 return
5164 case 'clear':
52 log.length = 0
65 await core.truncate(0)
5366 sock.write('ok\n')
5467 return
5568 case 'barrier':
5669 sock.write('ok\n')
5770 return
5871 case 'count':
59 sock.write(String(log.length) + '\n')
72 sock.write(String(core.length) + '\n')
6073 return
6174 default:
6275 sock.write('err unknown-verb ' + verb + '\n')
……@@ -65,29 +78,30 @@ function handleLine (line, sock) {
6578
6679const server = net.createServer({ allowHalfOpen: false }, (sock) => {
6780 let buf = ''
81 // Single ordered chain: guarantees appends apply in arrival order and that a
82 // later load/barrier observes all prior stores.
83 let tail = Promise.resolve()
6884 sock.on('data', (chunk) => {
6985 buf += chunk.toString()
7086 let nl
7187 while ((nl = buf.indexOf('\n')) !== -1) {
7288 const line = buf.slice(0, nl)
7389 buf = buf.slice(nl + 1)
74 handleLine(line, sock)
90 tail = tail.then(() => handleLine(line, sock)).catch((e) => console.error(e))
7591 }
7692 })
77 // Peer finished + disconnected. bare-net will not emit 'close' on its own;
78 // destroy to release the fd (the hyper-svc leak fix).
79 sock.on('end', () => sock.destroy())
93 sock.on('end', () => sock.destroy()) // release fd (hyper-svc leak fix)
8094 sock.on('error', () => sock.destroy())
8195})
8296
8397server.listen(sockPath, () => {
84 // Single line on stdout = readiness signal for run.sh / test harness.
85 console.log('hyper-atomspace-m0 listening ' + sockPath)
98 console.log('hyper-atomspace listening ' + sockPath + ' store=' + storageDir +
99 ' len=' + core.length)
86100})
87101
88// Clean shutdown so the socket file does not linger.
89function shutdown () {
102async function shutdown () {
90103 try { server.close() } catch (_) {}
104 try { await core.close() } catch (_) {}
91105 try { fs.unlinkSync(sockPath) } catch (_) {}
92106 process.exit(0)
93107}
experiments/m0-uds-bridge/m0_roundtrip.cc +113 -74
……@@ -1,17 +1,20 @@
11/*
2 * m0_roundtrip.cc — M0 bridge + codec round-trip harness.
2 * m0_roundtrip.cc — HyperStorageNode bridge harness (M0 + M1).
33 *
4 * Proves the HyperStorageNode data path with NO Hypercore and NO full
5 * StorageNode/guile-module boilerplate yet: build a small AtomSpace, encode each
6 * atom with the REAL opencog s-expr codec (Sexpr::encode_atom), ship it over a
7 * UNIX-domain socket to the Bare `hyper-atomspace` daemon (daemon.js), replay the
8 * log back, decode with the REAL codec (Sexpr::decode_atom) into a fresh
9 * AtomSpace, and gold-check that the two AtomSpaces are identical.
4 * Ships a small AtomSpace over a UNIX-domain socket to the Bare `hyper-atomspace`
5 * daemon (daemon.js), using the REAL opencog s-expr codec (Sexpr::encode_atom /
6 * Sexpr::decode_atom), then replays the log back and gold-checks identity.
107 *
11 * `HyperChannel` is the reusable AF_UNIX transport (adapted from
12 * CogSimpleStorage's do_send/do_recv, TCP -> UDS). At M1 it lifts straight into
13 * `HyperStorageNode : public StorageNode` (cf. CogChannel in cog-storage); here
14 * main() is just the test harness around it.
8 * `HyperChannel` is the reusable AF_UNIX transport (adapted from CogSimpleStorage
9 * do_send/do_recv, TCP->UDS); at the guile-module step it lifts into
10 * `HyperStorageNode : public StorageNode`. main() is the test harness.
11 *
12 * Modes:
13 * full (default) clear + store + barrier + load + gold-check (live append/replay)
14 * verify load + gold-check ONLY (run against a RESTARTED daemon on the
15 * same Hypercore dir -> proves durable deterministic replay, M1 #1)
16 * fork clear + store + load(full) + loadat(K) + prefix check
17 * (checkout at seq K = cheap fork, M1 #2)
1518 *
1619 * SPDX-License-Identifier: AGPL-3.0-or-later
1720 */
……@@ -35,11 +38,10 @@ using namespace opencog;
3538
3639// ---------------------------------------------------------------------------
3740// HyperChannel — newline-framed s-expr protocol over a UNIX-domain socket.
38// (The transport the future HyperStorageNode will embed.)
3941class HyperChannel
4042{
4143 int _fd = -1;
42 std::string _rbuf; // leftover bytes past a newline
44 std::string _rbuf;
4345
4446public:
4547 void open(const std::string& path)
……@@ -59,13 +61,9 @@ public:
5961 + strerror(errno));
6062 }
6163
62 void close_fd()
63 {
64 if (_fd >= 0) { ::close(_fd); _fd = -1; }
65 }
64 void close_fd() { if (_fd >= 0) { ::close(_fd); _fd = -1; } }
6665 ~HyperChannel() { close_fd(); }
6766
68 // Fire-and-forget send of one line (must include its own '\n').
6967 void send_line(const std::string& line)
7068 {
7169 size_t off = 0;
……@@ -77,7 +75,6 @@ public:
7775 }
7876 }
7977
80 // Read exactly one '\n'-terminated line; returns it without the newline.
8178 std::string recv_line()
8279 {
8380 for (;;)
……@@ -97,95 +94,137 @@ public:
9794 }
9895 }
9996
100 // Protocol verbs
10197 void store(const std::string& sexpr) { send_line("store " + sexpr + "\n"); }
10298 void clear() { send_line("clear\n"); (void) recv_line(); }
10399 void barrier() { send_line("barrier\n"); (void) recv_line(); }
104100 std::string load() { send_line("load\n"); return recv_line(); }
101 std::string loadat(int k)
102 {
103 send_line("loadat " + std::to_string(k) + "\n");
104 return recv_line();
105 }
105106};
106107
107108// ---------------------------------------------------------------------------
108// Enumerate every atom in `as`, encode each to its s-expr, return sorted vector.
109// Deterministic source AtomSpace. `order` returns the atoms in creation order
110// (nodes before the links that use them), so any prefix is a self-consistent
111// sub-graph — which is what makes the fork/checkout check crisp.
112static AtomSpacePtr build_src(HandleSeq& order)
113{
114 AtomSpacePtr as = createAtomSpace();
115 Handle cat = as->add_node(CONCEPT_NODE, "cat"); order.push_back(cat);
116 Handle animal = as->add_node(CONCEPT_NODE, "animal"); order.push_back(animal);
117 order.push_back(as->add_link(INHERITANCE_LINK, cat, animal));
118 Handle whale = as->add_node(CONCEPT_NODE, "whale"); order.push_back(whale);
119 Handle water = as->add_node(CONCEPT_NODE, "water"); order.push_back(water);
120 Handle livesIn = as->add_node(PREDICATE_NODE, "lives-in"); order.push_back(livesIn);
121 Handle lst = as->add_link(LIST_LINK, whale, water); order.push_back(lst);
122 order.push_back(as->add_link(EVALUATION_LINK, livesIn, lst));
123 return as;
124}
125
126// Every atom in `as`, encoded and sorted (for set comparison).
109127static std::vector<std::string> encoded_sorted(const AtomSpacePtr& as)
110128{
111129 HandleSeq all;
112 as->get_handles_by_type(all, ATOM, true /* subclasses */);
130 as->get_handles_by_type(all, ATOM, true);
113131 std::vector<std::string> out;
114 for (const Handle& h : all)
115 out.push_back(Sexpr::encode_atom(h));
132 for (const Handle& h : all) out.push_back(Sexpr::encode_atom(h));
116133 std::sort(out.begin(), out.end());
117134 return out;
118135}
119136
137// Decode a "(<atom><atom>…)" daemon reply into a fresh AtomSpace.
138static AtomSpacePtr decode_reply(const std::string& reply)
139{
140 AtomSpacePtr dst = createAtomSpace();
141 std::unordered_map<std::string, Handle> cache;
142 size_t l = reply.find('(');
143 size_t end = reply.rfind(')');
144 if (l == std::string::npos || end == std::string::npos || l >= end)
145 return dst;
146 l += 1;
147 size_t r = end;
148 while (true)
149 {
150 int pcnt = Sexpr::get_next_expr(reply, l, r, 0);
151 if (l == r) break;
152 if (0 < pcnt) break;
153 Handle h = Sexpr::decode_atom(reply, l, r, 0, cache);
154 dst->add_atom(h);
155 l = r + 1;
156 r = end;
157 }
158 return dst;
159}
160
120161int main(int argc, char** argv)
121162{
122163 if (argc < 2)
123164 {
124 std::cerr << "usage: m0_roundtrip <socket-path>\n";
165 std::cerr << "usage: m0_roundtrip <socket-path> [full|verify|fork]\n";
125166 return 2;
126167 }
127168 const std::string sockpath = argv[1];
169 const std::string mode = (argc >= 3) ? argv[2] : "full";
128170
129 // --- 1. Build a source AtomSpace: nodes, a link, a nested Eval/List. ---
130 AtomSpacePtr src = createAtomSpace();
131 Handle cat = src->add_node(CONCEPT_NODE, "cat");
132 Handle animal = src->add_node(CONCEPT_NODE, "animal");
133 src->add_link(INHERITANCE_LINK, cat, animal);
134
135 Handle whale = src->add_node(CONCEPT_NODE, "whale");
136 Handle water = src->add_node(CONCEPT_NODE, "water");
137 Handle livesIn = src->add_node(PREDICATE_NODE, "lives-in");
138 Handle lst = src->add_link(LIST_LINK, whale, water);
139 src->add_link(EVALUATION_LINK, livesIn, lst);
171 HandleSeq order;
172 AtomSpacePtr src = build_src(order);
173 std::vector<std::string> es = encoded_sorted(src);
140174
141 // --- 2. Store every atom over the UDS bridge. ---
142175 HyperChannel ch;
143176 ch.open(sockpath);
144 ch.clear();
145 for (const std::string& s : encoded_sorted(src))
146 ch.store(s);
147 ch.barrier();
148177
149 // --- 3. Replay the log; decode into a fresh AtomSpace. ---
150 std::string reply = ch.load();
151 AtomSpacePtr dst = createAtomSpace();
178 if (mode == "verify")
152179 {
153 std::unordered_map<std::string, Handle> cache;
154 size_t l = reply.find('(');
155 size_t end = reply.rfind(')');
156 if (l != std::string::npos && end != std::string::npos && l < end)
157 {
158 l += 1; // step past the outer '('
159 size_t r = end;
160 while (true)
161 {
162 int pcnt = Sexpr::get_next_expr(reply, l, r, 0);
163 if (l == r) break;
164 if (0 < pcnt) break; // unbalanced — malformed reply
165 Handle h = Sexpr::decode_atom(reply, l, r, 0, cache);
166 dst->add_atom(h);
167 l = r + 1;
168 r = end;
169 }
170 }
180 // Load ONLY — the daemon was restarted on the same Hypercore dir.
181 AtomSpacePtr dst = decode_reply(ch.load());
182 std::vector<std::string> ed = encoded_sorted(dst);
183 bool ok = (es == ed);
184 std::cout << "[verify] durable replay src=" << src->get_size()
185 << " dst=" << dst->get_size()
186 << (ok ? " GOLD #1 PASS\n" : " GOLD #1 FAIL\n");
187 return ok ? 0 : 1;
171188 }
172 ch.close_fd();
173189
174 // --- 4. Gold check: src and dst must be byte-identical atom sets. ---
175 std::vector<std::string> es = encoded_sorted(src);
176 std::vector<std::string> ed = encoded_sorted(dst);
177
178 std::cout << "src atoms: " << src->get_size()
179 << " dst atoms: " << dst->get_size() << "\n";
190 if (mode == "fork")
191 {
192 ch.clear();
193 for (const Handle& h : order) ch.store(Sexpr::encode_atom(h)); // creation order
194 ch.barrier();
195
196 AtomSpacePtr full = decode_reply(ch.load());
197 AtomSpacePtr forkK = decode_reply(ch.loadat(3)); // checkout @ seq 3
198
199 std::vector<std::string> ef = encoded_sorted(forkK);
200 std::vector<std::string> eF = encoded_sorted(full);
201
202 bool szF = (full->get_size() == 8);
203 bool szf = (forkK->get_size() == 3); // cat, animal, Inheritance(cat,animal)
204 bool subset = std::includes(eF.begin(), eF.end(), ef.begin(), ef.end());
205 bool strict = (forkK->get_size() < full->get_size());
206 bool ok = szF && szf && subset && strict;
207 std::cout << "[fork] full=" << full->get_size()
208 << " checkout@3=" << forkK->get_size()
209 << " subset=" << subset << " strict=" << strict
210 << (ok ? " GOLD #2 PASS\n" : " GOLD #2 FAIL\n");
211 return ok ? 0 : 1;
212 }
180213
214 // mode == full : live append + replay round-trip.
215 ch.clear();
216 for (const Handle& h : order) ch.store(Sexpr::encode_atom(h));
217 ch.barrier();
218 AtomSpacePtr dst = decode_reply(ch.load());
219 std::vector<std::string> ed = encoded_sorted(dst);
181220 bool ok = (es == ed) && (src->get_size() == dst->get_size());
221 std::cout << "[full] live round-trip src=" << src->get_size()
222 << " dst=" << dst->get_size()
223 << (ok ? " PASS\n" : " FAIL\n");
182224 if (not ok)
183225 {
184 std::cout << "MISMATCH\n src:\n";
185 for (const auto& s : es) std::cout << " " << s << "\n";
186 std::cout << " dst:\n";
187 for (const auto& s : ed) std::cout << " " << s << "\n";
226 std::cout << " src:\n"; for (auto& s : es) std::cout << " " << s << "\n";
227 std::cout << " dst:\n"; for (auto& s : ed) std::cout << " " << s << "\n";
188228 }
189 std::cout << (ok ? "M0 GOLD PASS" : "M0 GOLD FAIL") << "\n";
190229 return ok ? 0 : 1;
191230}
experiments/m0-uds-bridge/package-lock.json +540 -1
……@@ -10,7 +10,25 @@
1010 "dependencies": {
1111 "bare-fs": "^4.7.3",
1212 "bare-net": "^2.3.2",
13 "bare-process": "^4.5.0"
13 "bare-process": "^4.5.0",
14 "hypercore": "^11.33.5"
15 }
16 },
17 "node_modules/@hyperswarm/secret-stream": {
18 "version": "6.9.1",
19 "resolved": "https://registry.npmjs.org/@hyperswarm/secret-stream/-/secret-stream-6.9.1.tgz",
20 "integrity": "sha512-xb0S5y3YJwBakD77JOGBHlBxdp63mHClZoXBYoLv+9wH8e054ESKlmQptWqjJK5dv5VMUIVYOJB4MaOpB0JdGw==",
21 "license": "Apache-2.0",
22 "dependencies": {
23 "b4a": "^1.1.0",
24 "hypercore-crypto": "^3.3.1",
25 "noise-curve-ed": "^2.0.1",
26 "noise-handshake": "^4.0.0",
27 "sodium-secretstream": "^1.1.0",
28 "sodium-universal": "^5.0.0",
29 "streamx": "^2.14.0",
30 "timeout-refresh": "^2.0.0",
31 "unslab": "^1.3.0"
1432 }
1533 },
1634 "node_modules/b4a": {
……@@ -33,6 +51,50 @@
3351 "integrity": "sha512-zdc8l88eB11Jsz5rDd6sCAgv2kUFXgdrZWoMlgU6JMkfAi1/uuGFC3IEHswKbIRQTk5H3T5CMuechsXYxiaHlQ==",
3452 "license": "Apache-2.0"
3553 },
54 "node_modules/bare-addon-resolve": {
55 "version": "1.10.0",
56 "resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz",
57 "integrity": "sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA==",
58 "license": "Apache-2.0",
59 "dependencies": {
60 "bare-module-resolve": "^1.10.0",
61 "bare-semver": "^1.0.0"
62 },
63 "peerDependencies": {
64 "bare-url": "*"
65 },
66 "peerDependenciesMeta": {
67 "bare-url": {
68 "optional": true
69 }
70 }
71 },
72 "node_modules/bare-ansi-escapes": {
73 "version": "2.2.3",
74 "resolved": "https://registry.npmjs.org/bare-ansi-escapes/-/bare-ansi-escapes-2.2.3.tgz",
75 "integrity": "sha512-02ES4/E2RbrtZSnHJ9LntBhYkLA6lPpSEeP8iqS3MccBIVhVBlEmruF1I7HZqx5Q8aiTeYfQVeqmrU9YO2yYoQ==",
76 "license": "Apache-2.0",
77 "dependencies": {
78 "bare-stream": "^2.6.5"
79 },
80 "peerDependencies": {
81 "bare-buffer": "*"
82 },
83 "peerDependenciesMeta": {
84 "bare-buffer": {
85 "optional": true
86 }
87 }
88 },
89 "node_modules/bare-assert": {
90 "version": "1.2.0",
91 "resolved": "https://registry.npmjs.org/bare-assert/-/bare-assert-1.2.0.tgz",
92 "integrity": "sha512-c6uvgvTJBspTDxtVnPgrBKmLgcpW3Fp72NVKDLg6oT4QjQbhGtvrkHMhGYMK1sh4vjBHOBmuUalyt9hSzV37fQ==",
93 "license": "Apache-2.0",
94 "dependencies": {
95 "bare-inspect": "^3.1.2"
96 }
97 },
3698 "node_modules/bare-dns": {
3799 "version": "2.1.4",
38100 "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz",
……@@ -95,6 +157,36 @@
95157 "integrity": "sha512-VMb3tHo05gsnbu3OXTmkDiwTjMlOsbQmKoysKqKEyR09m77TuDrYFbj3Q5GGk10dAKsUHrnXmwCaeJqzVpB5ZA==",
96158 "license": "Apache-2.0"
97159 },
160 "node_modules/bare-inspect": {
161 "version": "3.1.4",
162 "resolved": "https://registry.npmjs.org/bare-inspect/-/bare-inspect-3.1.4.tgz",
163 "integrity": "sha512-jfW5KRA84o3REpI6Vr4nbvMn+hqVAw8GU1mMdRwUsY5yJovQamxYeKGVKGqdzs+8ZbG4jRzGUXP/3Ji/DnqfPg==",
164 "license": "Apache-2.0",
165 "dependencies": {
166 "bare-ansi-escapes": "^2.1.0",
167 "bare-type": "^1.0.0"
168 },
169 "engines": {
170 "bare": ">=1.18.0"
171 }
172 },
173 "node_modules/bare-module-resolve": {
174 "version": "1.12.2",
175 "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.2.tgz",
176 "integrity": "sha512-j+hiD5k99qec4KjJvYsI67q5AOBifmy9JG3oeMVxTmvrhn2sIdp8StrUvZu4YNgwTpO+NhniQG16N1ETDe1k5w==",
177 "license": "Apache-2.0",
178 "dependencies": {
179 "bare-semver": "^1.0.0"
180 },
181 "peerDependencies": {
182 "bare-url": "*"
183 },
184 "peerDependenciesMeta": {
185 "bare-url": {
186 "optional": true
187 }
188 }
189 },
98190 "node_modules/bare-net": {
99191 "version": "2.3.2",
100192 "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.2.tgz",
……@@ -161,6 +253,12 @@
161253 "bare-stdio": "^1.0.1"
162254 }
163255 },
256 "node_modules/bare-semver": {
257 "version": "1.1.0",
258 "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.1.0.tgz",
259 "integrity": "sha512-1Hw5qJ7hXdVt3uPUqjeFTuxyvBUJauvz5A1I2jk8gzjZMHp04n//6nV9MDbG9CMw78JHY2lGV0w6s//LrASm2w==",
260 "license": "Apache-2.0"
261 },
164262 "node_modules/bare-signals": {
165263 "version": "4.2.0",
166264 "resolved": "https://registry.npmjs.org/bare-signals/-/bare-signals-4.2.0.tgz",
……@@ -248,6 +346,15 @@
248346 "bare": ">=1.16.0"
249347 }
250348 },
349 "node_modules/bare-type": {
350 "version": "1.1.0",
351 "resolved": "https://registry.npmjs.org/bare-type/-/bare-type-1.1.0.tgz",
352 "integrity": "sha512-LdtnnEEYldOc87Dr4GpsKnStStZk3zfgoEMXy8yvEZkXrcCv9RtYDrUYWFsBQHtaB0s1EUWmcvS6XmEZYIj3Bw==",
353 "license": "Apache-2.0",
354 "engines": {
355 "bare": ">=1.2.0"
356 }
357 },
251358 "node_modules/bare-url": {
252359 "version": "2.4.5",
253360 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz",
……@@ -257,6 +364,35 @@
257364 "bare-path": "^3.0.0"
258365 }
259366 },
367 "node_modules/big-sparse-array": {
368 "version": "1.0.3",
369 "resolved": "https://registry.npmjs.org/big-sparse-array/-/big-sparse-array-1.0.3.tgz",
370 "integrity": "sha512-6RjV/3mSZORlMdpUaQ6rUSpG637cZm0//E54YYGtQg1c1O+AbZP8UTdJ/TchsDZcTVLmyWZcseBfp2HBeXUXOQ==",
371 "license": "MIT"
372 },
373 "node_modules/compact-encoding": {
374 "version": "3.3.0",
375 "resolved": "https://registry.npmjs.org/compact-encoding/-/compact-encoding-3.3.0.tgz",
376 "integrity": "sha512-e64XyzlBvTRJ3iScuU/U2w25Dglkm7fhrRbrGaHIwuTlNnzjRKMaQBCVl7mJRvZg7wI5a9wX1IVTXCuaAANNkw==",
377 "license": "Apache-2.0",
378 "dependencies": {
379 "b4a": "^1.3.0"
380 }
381 },
382 "node_modules/device-file": {
383 "version": "2.3.1",
384 "resolved": "https://registry.npmjs.org/device-file/-/device-file-2.3.1.tgz",
385 "integrity": "sha512-bmON44lwxJPle9N2OcH4tqM44pMGZKT8G6OkzXkz0urvqQ9LKkoQdTS6w0ztYfmLdUE27R4UUmx0+y2gEz4Jug==",
386 "license": "Apache-2.0",
387 "dependencies": {
388 "b4a": "^1.6.7",
389 "bare-fs": "^4.0.1",
390 "bare-path": "^3.0.0",
391 "fd-lock": "^2.1.0",
392 "fs-native-extensions": "^1.4.0",
393 "ready-resource": "^1.2.0"
394 }
395 },
260396 "node_modules/events-universal": {
261397 "version": "1.0.1",
262398 "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
……@@ -272,6 +408,379 @@
272408 "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
273409 "license": "MIT"
274410 },
411 "node_modules/fd-lock": {
412 "version": "2.2.0",
413 "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-2.2.0.tgz",
414 "integrity": "sha512-Il4jWBhjjgvUg+z8d0bC7ncXqB42caqKTUpnZ9jpcqiPmw8bkIixt7Kic1czbZPMxAQD/9kEqfZ5Dq77nSll0w==",
415 "license": "Apache-2.0",
416 "dependencies": {
417 "bare-fs": "^4.5.0",
418 "fs-native-extensions": "^1.4.4",
419 "ready-resource": "^1.2.0",
420 "resource-on-exit": "^1.0.0"
421 }
422 },
423 "node_modules/flat-tree": {
424 "version": "1.13.0",
425 "resolved": "https://registry.npmjs.org/flat-tree/-/flat-tree-1.13.0.tgz",
426 "integrity": "sha512-fT3HIuCPwHhFgJ20QYzDHgUG0zMmFg5cHvFiFo5h+QMSJ28TihsEVY0f8HGliuO+pOzmvjMx1odToeaEWkTnyQ==",
427 "license": "MIT"
428 },
429 "node_modules/fs-native-extensions": {
430 "version": "1.5.0",
431 "resolved": "https://registry.npmjs.org/fs-native-extensions/-/fs-native-extensions-1.5.0.tgz",
432 "integrity": "sha512-nuZLFm9mGCxvyi7Llww/J4OyifKCS21nEUTAmnlTZp3FObPOvA32aCedCmt4Z+8yk+caqfClNaSCfn/P7T7FLQ==",
433 "license": "Apache-2.0",
434 "dependencies": {
435 "require-addon": "^1.1.0",
436 "which-runtime": "^1.2.0"
437 }
438 },
439 "node_modules/generate-object-property": {
440 "version": "2.0.0",
441 "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-2.0.0.tgz",
442 "integrity": "sha512-KwuURPyqn2Mz8DdV29pJwQu0Y7tcsbkULr82eeOcY/ZllFK6I9Wm8dsRByIu7CKWlFi9BdW1b3mcXMp/kQBQsw==",
443 "license": "MIT",
444 "dependencies": {
445 "is-property": "^1.0.0"
446 }
447 },
448 "node_modules/generate-string": {
449 "version": "1.0.1",
450 "resolved": "https://registry.npmjs.org/generate-string/-/generate-string-1.0.1.tgz",
451 "integrity": "sha512-IfTY0dKZM43ACyGvXkbG7De7WY7MxTS5VO6Juhe8oJKpCmrYYXoqp/cJMskkpi0k9H8wuXq0H+eI898/BCqvXg==",
452 "license": "MIT"
453 },
454 "node_modules/hypercore": {
455 "version": "11.33.5",
456 "resolved": "https://registry.npmjs.org/hypercore/-/hypercore-11.33.5.tgz",
457 "integrity": "sha512-K88HURg5MvLjPxW8y6AzHDaf5rcaC81Ujaz4z8ugsl5zwucpmWRDf4YKXrIKGLSWyVSysSKywYDUYoAfMKJkWg==",
458 "license": "MIT",
459 "dependencies": {
460 "@hyperswarm/secret-stream": "^6.0.0",
461 "b4a": "^1.1.0",
462 "bare-events": "^2.2.0",
463 "big-sparse-array": "^1.0.3",
464 "compact-encoding": "^3.0.0",
465 "fast-fifo": "^1.3.0",
466 "flat-tree": "^1.9.0",
467 "hypercore-crypto": "^3.2.1",
468 "hypercore-errors": "^1.5.0",
469 "hypercore-id-encoding": "^1.2.0",
470 "hypercore-storage": "^3.0.0",
471 "is-options": "^1.0.1",
472 "nanoassert": "^2.0.0",
473 "protomux": "^3.5.0",
474 "quickbit-universal": "^2.2.0",
475 "random-array-iterator": "^1.0.0",
476 "safety-catch": "^1.0.1",
477 "sodium-universal": "^5.0.1",
478 "streamx": "^2.12.4",
479 "unslab": "^1.3.0",
480 "z32": "^1.0.0"
481 }
482 },
483 "node_modules/hypercore-crypto": {
484 "version": "3.7.0",
485 "resolved": "https://registry.npmjs.org/hypercore-crypto/-/hypercore-crypto-3.7.0.tgz",
486 "integrity": "sha512-SWxobptQf2V/+ZLCCDRTXqFzGfTPIkNIuDyLKXpEMfcpJ1/ec94N9aWgylHcWOHmRt14ng/KR7z0BugebWHK9Q==",
487 "license": "MIT",
488 "dependencies": {
489 "b4a": "^1.6.6",
490 "compact-encoding": "^3.0.0",
491 "sodium-universal": "^5.0.0"
492 }
493 },
494 "node_modules/hypercore-errors": {
495 "version": "1.5.0",
496 "resolved": "https://registry.npmjs.org/hypercore-errors/-/hypercore-errors-1.5.0.tgz",
497 "integrity": "sha512-5KQ/SuDxsvet+7qWA35Ay6zdD9WyAHQoyWHGcPUTbmJBd300gvNIJoi3oma7kp4TTCSzii6qYumNZe/s0j/saQ==",
498 "license": "Apache-2.0",
499 "dependencies": {
500 "hypercore-id-encoding": "^1.3.0"
501 }
502 },
503 "node_modules/hypercore-id-encoding": {
504 "version": "1.3.0",
505 "resolved": "https://registry.npmjs.org/hypercore-id-encoding/-/hypercore-id-encoding-1.3.0.tgz",
506 "integrity": "sha512-W6sHdGo5h7LXEsoWfKf/KfuROZmZRQDlGqJF2EPHW+noCK66Vvr0+zE6cL0vqQi18s0kQPeN7Sq3QyR0Ytc2VQ==",
507 "license": "Apache-2.0",
508 "dependencies": {
509 "b4a": "^1.5.3",
510 "z32": "^1.0.0"
511 }
512 },
513 "node_modules/hypercore-storage": {
514 "version": "3.1.2",
515 "resolved": "https://registry.npmjs.org/hypercore-storage/-/hypercore-storage-3.1.2.tgz",
516 "integrity": "sha512-Iw6C0Nx9QIIyFLfALiDNBUpkWTB19gqrxiK3igfTpp0STqqbL4AO0ywrY9+Mv9ynt0PNs/hTnlTW6WRe76iOUw==",
517 "license": "Apache-2.0",
518 "dependencies": {
519 "b4a": "^1.6.7",
520 "bare-path": "^3.0.0",
521 "compact-encoding": "^3.1.0",
522 "device-file": "^2.1.2",
523 "flat-tree": "^1.12.1",
524 "hypercore-crypto": "^3.4.2",
525 "hyperschema": "^1.21.0",
526 "index-encoder": "^3.3.2",
527 "resolve-reject-promise": "^1.0.0",
528 "rocksdb-native": "^3.11.0",
529 "scope-lock": "^1.2.4",
530 "streamx": "^2.21.1"
531 }
532 },
533 "node_modules/hyperschema": {
534 "version": "1.21.0",
535 "resolved": "https://registry.npmjs.org/hyperschema/-/hyperschema-1.21.0.tgz",
536 "integrity": "sha512-lEnIbLTUQf7w6FU6X+R3yUJhBwCzF4ewRnAaYOrPdcVWe1rbOf94PzMiXb5pBKxroCXzlrPLxVujxAsTrrHc8g==",
537 "license": "Apache-2.0",
538 "dependencies": {
539 "bare-fs": "^4.0.1",
540 "compact-encoding": "^3.0.0",
541 "generate-object-property": "^2.0.0",
542 "generate-string": "^1.0.1"
543 }
544 },
545 "node_modules/index-encoder": {
546 "version": "3.5.0",
547 "resolved": "https://registry.npmjs.org/index-encoder/-/index-encoder-3.5.0.tgz",
548 "integrity": "sha512-idZ1cxtZz2dRV6rUiaP9Xo99UjXbSzjcMacoQmxUMu/A7fEQcNPngvwDJYeWelQUS5XFlY71/or70lKn6XnwbQ==",
549 "license": "Apache-2.0",
550 "dependencies": {
551 "b4a": "^1.6.4"
552 }
553 },
554 "node_modules/is-options": {
555 "version": "1.0.2",
556 "resolved": "https://registry.npmjs.org/is-options/-/is-options-1.0.2.tgz",
557 "integrity": "sha512-u+Ai74c8Q74aS8BuHwPdI1jptGOT1FQXgCq8/zv0xRuE+wRgSMEJLj8lVO8Zp9BeGb29BXY6AsNPinfqjkr7Fg==",
558 "license": "MIT",
559 "dependencies": {
560 "b4a": "^1.1.1"
561 }
562 },
563 "node_modules/is-property": {
564 "version": "1.0.2",
565 "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
566 "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
567 "license": "MIT"
568 },
569 "node_modules/nanoassert": {
570 "version": "2.0.0",
571 "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
572 "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==",
573 "license": "ISC"
574 },
575 "node_modules/noise-curve-ed": {
576 "version": "2.1.0",
577 "resolved": "https://registry.npmjs.org/noise-curve-ed/-/noise-curve-ed-2.1.0.tgz",
578 "integrity": "sha512-zAzJx+VwZM3w6EA1hTmDhJfvAnCeBQn/1FAeZ0LtGxCcCtlAK/uJXQVF/eDVUOaAZ286lHlx77WJ+qj9SmsRRg==",
579 "license": "ISC",
580 "dependencies": {
581 "b4a": "^1.1.0",
582 "nanoassert": "^2.0.0",
583 "sodium-universal": "^5.0.0"
584 }
585 },
586 "node_modules/noise-handshake": {
587 "version": "4.2.0",
588 "resolved": "https://registry.npmjs.org/noise-handshake/-/noise-handshake-4.2.0.tgz",
589 "integrity": "sha512-9O/VTNX/E2/AToyMTTDU0J/4WhaXMTdqc2DHs9vf+snoZ0cenSBq0dNYTVV1snYYEkmo6QeRrYMxtqtoYnY+LA==",
590 "license": "Apache-2.0",
591 "dependencies": {
592 "b4a": "^1.1.0",
593 "nanoassert": "^2.0.0",
594 "sodium-universal": "^5.0.0"
595 }
596 },
597 "node_modules/protomux": {
598 "version": "3.11.0",
599 "resolved": "https://registry.npmjs.org/protomux/-/protomux-3.11.0.tgz",
600 "integrity": "sha512-Ze43XaNHbL6zQ/zJwVYvue7Aj8pDB1HNnISsrFhAur3291Y+Iu2fMhOpySD73J/32BoBIUYrhl07lJsBR/fUVA==",
601 "license": "MIT",
602 "dependencies": {
603 "b4a": "^1.3.1",
604 "compact-encoding": "^3.0.0",
605 "queue-tick": "^1.0.0",
606 "safety-catch": "^1.0.1",
607 "unslab": "^1.3.0"
608 }
609 },
610 "node_modules/queue-tick": {
611 "version": "1.0.1",
612 "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
613 "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
614 "license": "MIT"
615 },
616 "node_modules/quickbit-native": {
617 "version": "2.4.8",
618 "resolved": "https://registry.npmjs.org/quickbit-native/-/quickbit-native-2.4.8.tgz",
619 "integrity": "sha512-FcCcqI+nIAWGknqhtrYT5TSD7t/N+Xd8ctM+2PrIIBuwOi5hx0SxAvuPtzLIEMfT/2h9+fhBakUe2uALOHX6yw==",
620 "license": "Apache-2.0",
621 "optional": true,
622 "dependencies": {
623 "require-addon": "^1.1.0"
624 }
625 },
626 "node_modules/quickbit-universal": {
627 "version": "2.2.0",
628 "resolved": "https://registry.npmjs.org/quickbit-universal/-/quickbit-universal-2.2.0.tgz",
629 "integrity": "sha512-w02i1R8n7+6pEKTud8DfF8zbFY9o7RtPlUc3jWbtCkDKvhbx/AvV7oNnz4/TcmsPGpSJS+fq5Ud6RH6+YPvSGg==",
630 "license": "ISC",
631 "dependencies": {
632 "b4a": "^1.6.0",
633 "simdle-universal": "^1.1.0"
634 },
635 "optionalDependencies": {
636 "quickbit-native": "^2.2.0"
637 }
638 },
639 "node_modules/random-array-iterator": {
640 "version": "1.0.0",
641 "resolved": "https://registry.npmjs.org/random-array-iterator/-/random-array-iterator-1.0.0.tgz",
642 "integrity": "sha512-u7xCM93XqKEvPTP6xZp2ehttcAemKnh73oKNf1FvzuVCfpt6dILDt1Kxl1LeBjm2iNIeR49VGFhy4Iz3yOun+Q==",
643 "license": "MIT"
644 },
645 "node_modules/ready-resource": {
646 "version": "1.2.0",
647 "resolved": "https://registry.npmjs.org/ready-resource/-/ready-resource-1.2.0.tgz",
648 "integrity": "sha512-nfcco/8iAFV0M+2PYnmIc+/xY0iRb35d42HFHQ7AfjulbGEAFa+XWpByfwSyeVeiBoMLLFVMv1HixxNCqzSQ1g==",
649 "license": "MIT",
650 "dependencies": {
651 "bare-events": "^2.2.0"
652 }
653 },
654 "node_modules/refcounter": {
655 "version": "1.0.0",
656 "resolved": "https://registry.npmjs.org/refcounter/-/refcounter-1.0.0.tgz",
657 "integrity": "sha512-1WosVzUy0kPUaPMEtlNDwm99UsteALIhXXR8rerELoa63WkYIXAl0hxgwPFrIYBRWZPGUyekQ04FRtPJ7dHk9w==",
658 "license": "Apache-2.0"
659 },
660 "node_modules/require-addon": {
661 "version": "1.2.0",
662 "resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz",
663 "integrity": "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA==",
664 "license": "Apache-2.0",
665 "dependencies": {
666 "bare-addon-resolve": "^1.3.0"
667 },
668 "engines": {
669 "bare": ">=1.10.0"
670 }
671 },
672 "node_modules/resolve-reject-promise": {
673 "version": "1.1.0",
674 "resolved": "https://registry.npmjs.org/resolve-reject-promise/-/resolve-reject-promise-1.1.0.tgz",
675 "integrity": "sha512-LWsTOA91AqzBTjSGgX79Tc130pwcBK6xjpJEO+qRT5IKZ6bGnHKcc8QL3upUBcWuU8OTIDzKK2VNSwmmlqvAVg==",
676 "license": "MIT"
677 },
678 "node_modules/resource-on-exit": {
679 "version": "1.0.0",
680 "resolved": "https://registry.npmjs.org/resource-on-exit/-/resource-on-exit-1.0.0.tgz",
681 "integrity": "sha512-ViJwJAknCkLRJRPR+9SISQQ7R5eRgtdIHLJsM2hHx1MweAJbJxJ5XnMjjq0Lc7ZGv44ufzAqds1nKxiVkdy4ag==",
682 "license": "Apache-2.0"
683 },
684 "node_modules/rocksdb-native": {
685 "version": "3.17.1",
686 "resolved": "https://registry.npmjs.org/rocksdb-native/-/rocksdb-native-3.17.1.tgz",
687 "integrity": "sha512-33hbNSx57vbdM/kyP6dozy1eRLeiN69kTNcbPZ6AMkOjFtSY3G6O94TxKNgUIq53IQzFP6kClriKHeu4mu1q6w==",
688 "license": "Apache-2.0",
689 "dependencies": {
690 "compact-encoding": "^3.0.0",
691 "ready-resource": "^1.0.0",
692 "refcounter": "^1.0.0",
693 "require-addon": "^1.0.2",
694 "resolve-reject-promise": "^1.1.0",
695 "signal-promise": "^1.0.3",
696 "streamx": "^2.16.1"
697 },
698 "engines": {
699 "bare": ">=1.16.0"
700 }
701 },
702 "node_modules/safety-catch": {
703 "version": "1.0.3",
704 "resolved": "https://registry.npmjs.org/safety-catch/-/safety-catch-1.0.3.tgz",
705 "integrity": "sha512-Zq+J1TefpoEq/HTUabo0YXX5MNvttjWYODGohgPBO2jfko8Wqx3JYMgE823szDFVamdH5PlpByvfiWScTdSYDA==",
706 "license": "MIT"
707 },
708 "node_modules/scope-lock": {
709 "version": "1.2.4",
710 "resolved": "https://registry.npmjs.org/scope-lock/-/scope-lock-1.2.4.tgz",
711 "integrity": "sha512-BpSd8VCuCxW9ZitcdIC/vjs3gMaP9bRBL5nkHcyfX2VrS52n13/rHuBA2xJ/S/4DPuRdAO/Bk8pWd8eD/gHCIA==",
712 "license": "Apache-2.0"
713 },
714 "node_modules/signal-promise": {
715 "version": "1.0.3",
716 "resolved": "https://registry.npmjs.org/signal-promise/-/signal-promise-1.0.3.tgz",
717 "integrity": "sha512-WBgv0UnIq2C+Aeh0/n+IRpP6967eIx9WpynTUoiW3isPpfe1zu2LJzyfXdo9Tgef8yR/sGjcMvoUXD7EYdiz+g==",
718 "license": "MIT"
719 },
720 "node_modules/simdle-native": {
721 "version": "1.3.9",
722 "resolved": "https://registry.npmjs.org/simdle-native/-/simdle-native-1.3.9.tgz",
723 "integrity": "sha512-Isc8sP4OiiIU0mpslD4GHEnR0VQWvR/54WN7YtwEDkNdTJVWtpmvsSvsgRlw5BNGxdYXlVRegdnrSu10H/PhvA==",
724 "license": "Apache-2.0",
725 "optional": true,
726 "dependencies": {
727 "b4a": "^1.6.0",
728 "require-addon": "^1.1.0"
729 }
730 },
731 "node_modules/simdle-universal": {
732 "version": "1.1.2",
733 "resolved": "https://registry.npmjs.org/simdle-universal/-/simdle-universal-1.1.2.tgz",
734 "integrity": "sha512-3n3w1bs+uwgHKQjt6arez83EywNlhZzYvNOhvAASTl/8KqNIcqr6aHyGt3JRlfuUC7iB0tomJRPlJ2cRGIpBzA==",
735 "license": "ISC",
736 "dependencies": {
737 "b4a": "^1.6.0"
738 },
739 "optionalDependencies": {
740 "simdle-native": "^1.1.1"
741 }
742 },
743 "node_modules/sodium-native": {
744 "version": "5.1.0",
745 "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-5.1.0.tgz",
746 "integrity": "sha512-3RxgyWyJlhTsABPnJVpCI5CoTDANZTqqFrEPqr+kjfnRaBihpVtMUE3yTF40ukdoB1APXeoBNKF3MzZAIHg39g==",
747 "license": "MIT",
748 "dependencies": {
749 "bare-assert": "^1.2.0",
750 "require-addon": "^1.1.0",
751 "which-runtime": "^1.2.1"
752 },
753 "engines": {
754 "bare": ">=1.16.0"
755 }
756 },
757 "node_modules/sodium-secretstream": {
758 "version": "1.2.0",
759 "resolved": "https://registry.npmjs.org/sodium-secretstream/-/sodium-secretstream-1.2.0.tgz",
760 "integrity": "sha512-q/DbraNFXm1KfCiiZvapmz5UC3OlpirYFIvBK2MhGaOFSb3gRyk8OXTi17UI9SGfshQNCpsVvlopogbzZNyW6Q==",
761 "license": "MIT",
762 "dependencies": {
763 "b4a": "^1.1.1",
764 "sodium-universal": "^5.0.0"
765 }
766 },
767 "node_modules/sodium-universal": {
768 "version": "5.0.1",
769 "resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-5.0.1.tgz",
770 "integrity": "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q==",
771 "license": "MIT",
772 "dependencies": {
773 "sodium-native": "^5.0.1"
774 },
775 "peerDependencies": {
776 "sodium-javascript": "~0.8.0"
777 },
778 "peerDependenciesMeta": {
779 "sodium-javascript": {
780 "optional": true
781 }
782 }
783 },
275784 "node_modules/streamx": {
276785 "version": "2.28.0",
277786 "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz",
……@@ -300,6 +809,36 @@
300809 "dependencies": {
301810 "b4a": "^1.6.4"
302811 }
812 },
813 "node_modules/timeout-refresh": {
814 "version": "2.0.1",
815 "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-2.0.1.tgz",
816 "integrity": "sha512-SVqEcMZBsZF9mA78rjzCrYrUs37LMJk3ShZ851ygZYW1cMeIjs9mL57KO6Iv5mmjSQnOe/29/VAfGXo+oRCiVw==",
817 "license": "MIT"
818 },
819 "node_modules/unslab": {
820 "version": "1.3.0",
821 "resolved": "https://registry.npmjs.org/unslab/-/unslab-1.3.0.tgz",
822 "integrity": "sha512-YATkfKAFj47kTzmiQrWXMyRvaVrHsW6MEALa4bm+FhiA2YG4oira+Z3DXN6LrYOYn2Y8eO94Lwl9DOHjs1FpoQ==",
823 "license": "Apache-2.0",
824 "dependencies": {
825 "b4a": "^1.6.6"
826 }
827 },
828 "node_modules/which-runtime": {
829 "version": "1.4.0",
830 "resolved": "https://registry.npmjs.org/which-runtime/-/which-runtime-1.4.0.tgz",
831 "integrity": "sha512-0ugbP4CJW4e2D20jvEcC4973dCgIaHI4Rw1PT+26U9zEve7FyYdWAIwUnoeOYvoCfn+wXHoHTKb1KhkYlb60Pw==",
832 "license": "Apache-2.0"
833 },
834 "node_modules/z32": {
835 "version": "1.1.0",
836 "resolved": "https://registry.npmjs.org/z32/-/z32-1.1.0.tgz",
837 "integrity": "sha512-1WUHy+VS6d0HPNspDxvLssBbeQjXMjSnpv0vH82vRAUfg847NmX3OXozp/hRP5jPhxBbrVzrgvAt+UsGNzRFQQ==",
838 "license": "MIT",
839 "dependencies": {
840 "b4a": "^1.5.3"
841 }
303842 }
304843 }
305844}
experiments/m0-uds-bridge/package.json +2 -1
……@@ -7,6 +7,7 @@
77 "dependencies": {
88 "bare-fs": "^4.7.3",
99 "bare-net": "^2.3.2",
10 "bare-process": "^4.5.0"
10 "bare-process": "^4.5.0",
11 "hypercore": "^11.33.5"
1112 }
1213}
experiments/m0-uds-bridge/run.sh +49 -24
……@@ -1,40 +1,65 @@
11#!/usr/bin/env bash
2# M0 end-to-end: build the C++ harness, start the Bare daemon, round-trip a small
3# AtomSpace through the UDS bridge, gold-check identity. Exits 0 on PASS.
2# HyperStorageNode bridge — M0 + M1 end-to-end.
3# full : live append + replay round-trip over a real Hypercore
4# verify : restart the daemon on the SAME Hypercore dir, replay -> GOLD #1
5# (durable deterministic replay)
6# fork : checkout at seq K (read fewer blocks -> earlier graph) -> GOLD #2
7# Exits 0 iff all three pass.
48set -euo pipefail
59cd "$(dirname "$0")"
610
7# Short socket path: AF_UNIX sun_path caps at ~108 bytes, so NOT the scratchpad.
8SOCK="$(mktemp -u /tmp/m0-XXXXXX.sock)"
9DLOG="$(mktemp /tmp/m0-daemon-XXXXXX.log)"
11# Short paths: AF_UNIX sun_path caps at ~108 bytes.
12WORK="$(mktemp -d /tmp/m1-XXXXXX)"
13SOCK="$WORK/svc.sock"
14STORE1="$WORK/store1"
15STORE2="$WORK/store2"
1016DPID=""
1117
1218cleanup() {
13 # `bare` is an nvm shim that execs a child runtime, so killing $DPID alone can
14 # leave the child. Also match the daemon by its unique (mktemp) socket path.
19 # `bare` is an nvm shim that execs a child runtime; kill $DPID AND match the
20 # daemon by its unique socket path.
1521 [ -n "$DPID" ] && kill -9 "$DPID" 2>/dev/null || true
16 pkill -9 -f "daemon.js ${SOCK}\$" 2>/dev/null || true
17 rm -f "$SOCK" "$DLOG"
22 pkill -9 -f "daemon.js $SOCK" 2>/dev/null || true
23 rm -rf "$WORK"
1824}
1925trap cleanup EXIT
2026
21# 1. deps + build
22[ -d node_modules/bare-net ] || npm install --silent
27start_daemon() { # $1=storage-dir
28 bare daemon.js "$SOCK" "$1" > "$WORK/d.log" 2>&1 &
29 DPID=$!
30 for _ in $(seq 1 100); do
31 grep -q listening "$WORK/d.log" && return 0
32 sleep 0.05
33 done
34 echo "daemon failed to start:"; cat "$WORK/d.log"; return 1
35}
36stop_daemon() {
37 [ -n "$DPID" ] && kill -9 "$DPID" 2>/dev/null || true
38 pkill -9 -f "daemon.js $SOCK" 2>/dev/null || true
39 DPID=""
40 sleep 0.2 # let the core close and the fd release before rebind
41}
42
43# deps + build
44[ -d node_modules/hypercore ] || npm install --silent
2345g++ -std=gnu++20 -O2 -I/usr/local/include m0_roundtrip.cc \
2446 -L/usr/local/lib/opencog -Wl,-rpath,/usr/local/lib/opencog \
2547 -latomspace -lsexpr -latombase -latom_types \
2648 -o m0_roundtrip
2749
28# 2. start the Bare daemon, wait for its readiness line
29bare daemon.js "$SOCK" > "$DLOG" 2>&1 &
30DPID=$!
31for _ in $(seq 1 100); do
32 grep -q listening "$DLOG" && break
33 sleep 0.05
34done
35if ! grep -q listening "$DLOG"; then
36 echo "daemon failed to start:"; cat "$DLOG"; exit 1
37fi
38
39# 3. run the harness (build src AtomSpace -> UDS -> replay -> gold check)
40./m0_roundtrip "$SOCK"
50# Phase 1 — live append + replay onto Hypercore STORE1
51start_daemon "$STORE1"
52./m0_roundtrip "$SOCK" full
53stop_daemon
54
55# Phase 2 — restart on the SAME store, replay only (durable determinism, GOLD #1)
56start_daemon "$STORE1"
57./m0_roundtrip "$SOCK" verify
58stop_daemon
59
60# Phase 3 — fresh store, fork/checkout at seq K (GOLD #2)
61start_daemon "$STORE2"
62./m0_roundtrip "$SOCK" fork
63stop_daemon
64
65echo "M1 ALL PASS"