Files
orgchain/tests/charter.test.js
T
teahubxyzandClaude Opus 5.5 5a7f11e49d Orgchain v1.14.1: a belt counts only on its seat's own sat
Placement is now a rule of lineage/v0, not just how Orgchain inscribes:
an award counts only if it is inscribed on its recipient's own sat, so any
indexer can check that a belt is soulbound. The reducer compares sats
(satOf): the lab's sat numbers, ord's, or, without ord's sat index, its
satpoints, which two inscriptions share exactly when they share a sat. ord
events now carry the sat number when ord has one. Belts inscribed anywhere
else, as before v1.14, are rejected.

A promotion is another reinscription on the same sat, over the belt before
it: each badge keeps its skill's earlier belts, and Inspect shows the
ladder ("re-inscribed over white (beat 5)"). The sample's sol now goes
white, then green. An award and its recipient's own close no longer
conflict within a block, since both spend the recipient's inscription.

Rehearsed again on Bitcoin Core regtest from height 178: sixteen beats and
133 transactions; ord shows sol's sat carrying sol, its white belt and its
green belt, in order, each belt charmed reinscription and vindicated, and
the compare matches. The fixture is re-recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H4upF5LVwmPDDqrhdUfnXh
2026-10-15 16:10:18 -07:00

106 lines
8.1 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { PROTOCOL, isSeat, reduce, standing, summary } from '../src/orgchain/lineage.js';
import { emptyLab, setTempo } from '../src/orgchain/store.js';
import { act, lineageState, send } from '../src/orgchain/actions.js';
import { holderOf, keyOf, secretsOf } from '../src/orgchain/keys.js';
import { SAT, payerOf } from '../src/orgchain/money.js';
let n = 0;
// Each inscription on a sat of its own, but a belt on its recipient's, as the chain puts it (SPEC.md, section 7).
const sats = new Map(), ev = (op, parent = null, meta = {}, height = 1) => {
const id = `${String(++n).padStart(64, '0')}i0`, sat = op === 'award' && sats.has(meta.to) ? sats.get(meta.to) : n * 10_000;
sats.set(id, sat);
return { id, sat, status: height === null ? 'pending' : 'confirmed', height, metadata: { op, ...meta }, parent, protocol: PROTOCOL };
};
const charter = (by, meta, height = 2) => ev('charter', by.id, meta, height);
test('a charter records a legal form: a node charters itself, and a series is chartered by its master', () => {
const root = ev('found', null, { name: 'acme' }), ops = ev('birth', root.id, { name: 'ops' }), lab = ev('birth', ops.id, { name: 'lab' }),
bot = ev('birth', ops.id, { name: 'bot', kind: 'agent' }), other = ev('found', null, { name: 'other' });
const filing = 'ab'.repeat(32), tries = [
[charter(root, { form: 'series', of: ops.id }), 'acme is not chartered as a series LLC'],
[charter(root, { form: 'series-llc', jurisdiction: 'US-WY', legal: 'Acme Holdings LLC', provider: 'doola', filing }), 'ok'],
[charter(root, { form: 'series', of: ops.id }), 'ok'],
[charter(root, { form: 'series', of: lab.id }), 'ok'],
[charter(root, { form: 'series', of: bot.id }), 'only orgs become series'],
[charter(other, { form: 'series', of: ops.id }), 'a series must descend from its master'],
[charter(root, { form: 'series', of: ops.id, jurisdiction: 'US-DE' }), "a series takes its master's jurisdiction"],
[charter(ops, { form: 'llc' }), 'a jurisdiction is an ISO code such as US-WY'],
[charter(ops, { form: 'llc', jurisdiction: 'wyoming' }), 'a jurisdiction is an ISO code such as US-WY'],
[charter(ops, { form: 'sole' }), 'a sole proprietor is a person: a holding or an agent'],
[charter(bot, { form: 'llc', jurisdiction: 'US-DE' }), 'an agent graduates before it incorporates'],
[charter(bot, { form: 'sole' }), 'ok'],
[charter(ops, { form: 'gmbh', jurisdiction: 'DE' }), "a charter's form is sole, llc, series-llc, series, corp"],
[charter(ops, { form: 'llc', jurisdiction: 'US-WY', filing: 'nope' }), 'a filing is the SHA-256 of the filed documents, in hex'],
[charter(ops, { form: 'llc', jurisdiction: 'US-WY', provider: 'Doola Inc' }), /^a provider's name follows the name rule/],
[charter(ops, { form: 'llc', jurisdiction: 'US-WY', of: root.id }), 'a node charters itself; only a series is chartered by its master'],
];
const s = reduce([root, ops, lab, bot, other, ...tries.map(([e]) => e)]);
tries.forEach(([e, want]) => {
const entry = s.log.find(x => x.id === e.id), got = entry.ok ? 'ok' : entry.why;
if (want instanceof RegExp) assert.match(got, want); else assert.equal(got, want);
});
const node = e => s.nodes.get(e.id);
assert.deepEqual(node(root).charter, { id: tries[1][0].id, beat: 2, form: 'series-llc', jurisdiction: 'US-WY', legal: 'Acme Holdings LLC',
provider: 'doola', filing, master: null });
assert.deepEqual([node(ops).charter.form, node(ops).charter.master, node(lab).charter.master], ['series', root.id, root.id]);
assert.equal(node(bot).charter.form, 'sole');
assert.deepEqual([ops, lab, bot].map(e => standing(s, node(e))), [{ ok: true, why: '' }, { ok: true, why: '' }, { ok: true, why: '' }]);
assert.equal(summary(s.log.find(x => x.id === tries[1][0].id), s), 'charter acme · series LLC (US-WY)');
assert.equal(summary(s.log.find(x => x.id === tries[2][0].id), s), 'charter ops as a series of acme');
});
test("a series' standing follows the tree: graduating, its master dropping series, or a close lapses it, in any order", () => {
const root = ev('found', null, { name: 'acme' }), ops = ev('birth', root.id, { name: 'ops' }), lab = ev('birth', ops.id, { name: 'lab' });
const master = charter(root, { form: 'series-llc', jurisdiction: 'US-WY' }), series = charter(root, { form: 'series', of: ops.id }, 3);
const kid = charter(root, { form: 'series', of: lab.id }, 3), grad = ev('graduate', root.id, { of: ops.id }, 3);
const base = [root, ops, lab, master];
for (const s of [reduce([...base, series, kid, grad]), reduce([...base, grad, series, kid])]) {
assert.equal(s.nodes.get(ops.id).charter.form, 'series', 'a graduate keeps its parent, so it still descends from its master');
assert.deepEqual(standing(s, s.nodes.get(ops.id)), { ok: false, why: "ops is no longer in acme's holding" });
assert.deepEqual(standing(s, s.nodes.get(lab.id)), { ok: false, why: "lab is no longer in acme's holding" });
}
// Once it graduates, ops charters itself as an LLC, and that stands.
const own = reduce([...base, series, grad, charter(ops, { form: 'llc', jurisdiction: 'US-DE', legal: 'Ops LLC' }, 4)]);
assert.deepEqual(standing(own, own.nodes.get(ops.id)), { ok: true, why: '' });
// The master drops series, so its series lapse; a closed series is closed.
const s = reduce([...base, series, kid, charter(root, { form: 'llc', jurisdiction: 'US-WY' }, 4), ev('close', lab.id, {}, 4)]);
assert.deepEqual(standing(s, s.nodes.get(ops.id)), { ok: false, why: 'acme no longer holds series' });
assert.deepEqual(standing(s, s.nodes.get(lab.id)), { ok: false, why: 'lab is closed' });
});
test('a seat graduates into a holding of its own, and can then birth, award and incorporate', () => {
const root = ev('found', null, { name: 'guild' }), ada = ev('birth', root.id, { name: 'ada', kind: 'agent' }), bo = ev('birth', root.id, { name: 'bo', kind: 'agent' });
const s = reduce([root, ada, bo, ev('graduate', root.id, { of: ada.id }, 2), ev('birth', ada.id, { name: 'studio' }, 3),
ev('award', ada.id, { to: bo.id, skill: 'pair', belt: 'white' }, 3), charter(ada, { form: 'llc', jurisdiction: 'US-WY', legal: 'Ada LLC' }, 3)]);
assert.ok(s.log.every(e => e.ok), s.log.filter(e => !e.ok).map(e => e.why).join('; '));
const node = s.nodes.get(ada.id);
assert.deepEqual([node.kind, node.edge, node.root === node.id, isSeat(node), isSeat(s.nodes.get(bo.id))], ['agent', 'adopted', true, false, true]);
assert.deepEqual(s.roots.map(r => r.name), ['guild', 'ada']);
assert.equal(s.nodes.get(bo.id).badges[0].by, ada.id);
});
test('in the lab a seat goes independent: its own root and keys, its money along, and acts of its own', () => {
const lab = emptyLab();
const root = act(lab, 'found', null, { name: 'guild' }), ada = act(lab, 'birth', root, { name: 'ada', kind: 'agent' });
send(lab, root, ada, SAT);
const before = payerOf(lab.keys, lineageState(lab), lineageState(lab).nodes.get(ada)).address;
const freed = act(lab, 'graduate', root, { of: ada });
const s = lineageState(lab), node = s.nodes.get(ada), k = keyOf(lab.keys, s, node);
assert.deepEqual([k.account, k.from, holderOf(lab, s, ada).who, node.rooted], [0, 'ada root', 'own', freed]);
assert.equal(secretsOf(lab.keys, s, node).seed.mnemonic, lab.keys.adopted[freed]);
const purse = payerOf(lab.keys, s, node);
assert.notEqual(purse.address, before);
assert.ok(lab.chain.balance(purse.script) > 0.99 * SAT, 'its money moved to its new SegWit address');
setTempo(lab, 'each');
const studio = act(lab, 'birth', ada, { name: 'studio' });
act(lab, 'charter', ada, { form: 'llc', jurisdiction: 'US-WY', legal: 'Ada LLC', provider: 'doola' });
act(lab, 'charter', ada, { form: 'series-llc', jurisdiction: 'US-WY', legal: 'Ada LLC' });
act(lab, 'charter', ada, { form: 'series', of: studio });
const after = lineageState(lab);
assert.deepEqual([after.nodes.get(ada).charter.form, after.nodes.get(studio).charter.form, standing(after, after.nodes.get(studio)).ok],
['series-llc', 'series', true]);
assert.throws(() => act(lab, 'charter', studio, { form: 'sole' }), /A sole proprietor is a person/);
});