Arboricx bundle format 1.1

We don't need SHA verification or Merkle dags in our transport bundle. Content
stores can handle both bundle and term verification and hashing.
This commit is contained in:
2026-05-11 19:53:37 -05:00
parent e0b1e95729
commit 31bf7094f4
45 changed files with 4032 additions and 7127 deletions

View File

@@ -1,80 +1,113 @@
import { strictEqual, ok } from "node:assert";
import { describe, it } from "node:test";
import { apply, isLeaf, isStem, isFork } from "../src/tree.js";
import { reduce } from "../src/cli.js";
import { readFileSync } from 'node:fs';
import { strictEqual, ok } from 'node:assert';
import { describe, it } from 'node:test';
import {
findLib,
init,
free,
leaf,
stem,
fork,
app,
reduce,
toBool,
toString,
toNumber,
loadBundleDefault,
ofString,
ofNumber,
} from '../src/lib.js';
describe("tree — basic types", () => {
it("Leaf is empty array", () => {
ok(isLeaf([]));
ok(!isStem([]));
ok(!isFork([]));
const libPath = findLib();
describe('tree construction', () => {
it('leaf returns a positive index', () => {
const ctx = init(libPath);
try {
const idx = leaf(ctx);
ok(idx > 0);
} finally {
free(ctx);
}
});
it("Stem is single-element array", () => {
ok(isStem([[]]));
ok(!isLeaf([[]]));
it('stem wraps a child', () => {
const ctx = init(libPath);
try {
const l = leaf(ctx);
const s = stem(ctx, l);
ok(s > 0);
ok(s !== l);
} finally {
free(ctx);
}
});
it("Fork is two-element array", () => {
ok(isFork([[], []]));
ok(!isLeaf([[], []]));
it('fork combines left and right', () => {
const ctx = init(libPath);
try {
const a = leaf(ctx);
const b = leaf(ctx);
const f = fork(ctx, a, b);
ok(f > 0);
ok(f !== a && f !== b);
} finally {
free(ctx);
}
});
});
describe("tree — apply rules", () => {
// Leaf = [], Stem = [child], Fork = [right, left]
it("apply(Leaf, b) = Stem(b)", () => {
const b = []; // Leaf
const result = apply([], b);
ok(isStem(result), "Stem(b) should be a Stem");
strictEqual(result[0], b);
describe('reduction — booleans', () => {
it('true.arboricx reduces to boolean true', () => {
const ctx = init(libPath);
try {
const bundle = readFileSync('../../test/fixtures/true.arboricx');
const root = loadBundleDefault(ctx, bundle);
const result = reduce(ctx, root, 1_000_000n);
strictEqual(toBool(ctx, result), true);
} finally {
free(ctx);
}
});
it("apply(Stem(a), b) = Fork(a, b)", () => {
const a = []; // Leaf
const b = []; // Leaf
const result = apply([a], b);
ok(isFork(result), "Fork(a, b) should be a Fork");
// Fork = [right, left] = [b, a]
strictEqual(result[0], b);
strictEqual(result[1], a);
});
it("apply(Fork(Leaf, a), _) = a", () => {
// Fork(Leaf, a) = [a, Leaf]
const a = []; // Leaf
const result = apply([a, []], []);
strictEqual(result, a);
ok(isLeaf(result));
it('false.arboricx reduces to boolean false', () => {
const ctx = init(libPath);
try {
const bundle = readFileSync('../../test/fixtures/false.arboricx');
const root = loadBundleDefault(ctx, bundle);
const result = reduce(ctx, root, 1_000_000n);
strictEqual(toBool(ctx, result), false);
} finally {
free(ctx);
}
});
});
describe("tree — reduction", () => {
it("reduces Leaf to Leaf", () => {
const result = reduce([], 100);
ok(isLeaf(result));
});
it("reduces Stem Leaf to Stem Leaf", () => {
const result = reduce([[]], 100);
ok(isStem(result));
ok(isLeaf(result[0]));
});
it("reduces Fork Leaf Leaf to Fork Leaf Leaf", () => {
const result = reduce([[], []], 100);
ok(isFork(result));
ok(isLeaf(result[0]));
ok(isLeaf(result[1]));
});
it("S combinator applied to Leaf reduces", () => {
// S = t (t (t t)) t = Fork (Fork (Fork Leaf Leaf) Leaf) Leaf
// In array form: [[[], []], [], []]
const s = [[], [[[], []], []]];
const leaf = [];
const result = reduce([s, leaf], 100);
ok(Array.isArray(result), "S Leaf should reduce to an array");
describe('reduction — id', () => {
it('id applied to string returns the string', () => {
const ctx = init(libPath);
try {
const bundle = readFileSync('../../test/fixtures/id.arboricx');
const idRoot = loadBundleDefault(ctx, bundle);
const arg = ofString(ctx, 'hello');
const applied = app(ctx, idRoot, arg);
const result = reduce(ctx, applied, 1_000_000n);
strictEqual(toString(ctx, result), 'hello');
} finally {
free(ctx);
}
});
});
describe('reduction — numbers', () => {
it('ofNumber round-trips through toNumber', () => {
const ctx = init(libPath);
try {
const num = ofNumber(ctx, 42);
strictEqual(toNumber(ctx, num), 42);
} finally {
free(ctx);
}
});
});