A new lineage/v0 op, charter, records a node's legal form: sole proprietor, LLC, series LLC, series or corporation, with a jurisdiction (ISO 3166), a legal name, who formed it and a SHA-256 of the filings. Legal form is an attribute, so a node keeps its inscription, keys and history whatever form it takes, and the newest charter counts. A node charters itself; a series is chartered by its master, an ancestor chartered as a series LLC. Whether a charter stands is derived from the tree, never stored: a series lapses if it graduates or its master closes or stops holding series, so charters commute with graduations and closes in any block order. Agents can graduate: a seat goes independent as a holding of its own, with its own root and keys and its money along, and can then birth, award and incorporate. Charter is the tenth verb, and the tree tags each node with its form. Charter hashes a filing from a file in the tab. The sample charters yolopreneur as a Wyoming series LLC with its ventures as series, and lineage graduates into Lineage LLC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H4upF5LVwmPDDqrhdUfnXh
102 lines
7.8 KiB
JavaScript
102 lines
7.8 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;
|
|
const ev = (op, parent = null, meta = {}, height = 1) => ({ id: `${String(++n).padStart(64, '0')}i0`, 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;
|
|
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], [0, 'ada root', 'own']);
|
|
assert.equal(secretsOf(lab.keys, s, node).seed.mnemonic, lab.keys.adopted[ada]);
|
|
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/);
|
|
});
|