Files

58 lines
5.7 KiB
Markdown
Raw Permalink Normal View History

2026-10-04 23:03:47 +00:00
# AGENTS.md
Orgchain is lineage's app for creating and operating lineage holdings on Super Testnet's toy chain.
- Test-only, always: no mainnet funds, no hidden signing, no custody, and nothing presented as a real key.
- Lineage semantics live in one place, `src/orgchain/lineage.js`, and `SPEC.md` says the same in words. The UI never
interprets events itself, and every act is vetted by that reducer before it is signed. A new op or rule means a
reducer change, its tests, the README's table and `SPEC.md`.
- Whatever signs must stay valid on real Bitcoin. After changing how transactions or envelopes are built, rerun the
regtest rehearsal and its comparison (`tools/regtest/README.md`) and refresh the fixture it records.
- The engine (`src/adapters`, `src/upstream`, `src/storage.js`, `src/miner.js`) is Super Testnet's. Compose with it
rather than rewriting it, and keep its tests passing. Preserve upstream licenses and provenance. Its local
2026-10-15 14:51:52 -07:00
changes are P2WPKH payments, a coinbase split across up to 64 outputs, ordinary spends of up to 64 inputs and
outputs whose key-path signatures may carry 0x83, a three-input reveal that inscribes on a sat another key holds
(a belt) and returns both coins unchanged, coins imported from a real chain, and BIP-341/342 checks of reveals'
script paths, all in `src/adapters/chain.js` (PROVENANCE.md); keep them small and tested.
- Money lives in `src/orgchain/money.js`: beats pay the holdings (split by hashrate, or all to the last act; under
Mainnet none mine, and the lab wallet funds them), sends spend SegWit coins only, so an inscription can never leave
as change, and balances are read off the chain, never stored. Gas (`src/orgchain/actions.js`): every act is paid by
the actor's own keys and checked before anything is signed; the lab wallet pays only for foundings and for holdings
that predate lab keys.
- Deals live in `src/orgchain/offers.js`, both sides of the PSBT: an offer (the buyer pre-signs the whole transaction
and the holder countersigns) and an ask (the holder signs the lot's input alone, SIGHASH_SINGLE|ANYONECANPAY, and any
buyer completes it behind a dummy of its own). Offers and asks are signatures kept in the lab, never chain state, and
2026-10-15 14:51:52 -07:00
who holds a lot is read off the chain, never from metadata. An org sells with its tree, and a holding whole, by its
owner (the lab wallet): cash-free, and frozen with everything in it while listed or sold (`actions.js` cashOut,
frozenWhy; a listed holding mines nothing). A tree travels as one output (`bundle` for an ask; an offer merges its
inputs) and splits back by the deal's layout once adopted (`unbundle`): one output per inscribed sat, never two
sats' inscriptions left sharing a coin, or selling one would sell the other. Its buyer's keys sign the adoption and
the split: never sign for the buyer at the seller's act.
- Belts are soulbound (`src/orgchain/belts.js`): a belt counts only when it is inscribed on its recipient's own sat
(the reducer compares sats with `satOf`: the lab's sat numbers, ord's, or else ord's satpoints), and the lab puts it
there in one three-input reveal that the recipient's key co-signs, so it goes wherever its node goes; a promotion is
another reinscription on that sat. Count and split coins by inscribed sat, never by inscription, since a node shares
its sat with its belts, and never make a belt a lot. The compare checks ord's satpoints and charms (`charmsOf` models
the ones lineage's inscriptions earn); keep that model in step with ord.
- Moves (`join`, `adopt`): neither half's effect may depend on their order within a block, since a miner may put them
either way; the move records both halves. An old parent keeps a moved child in `children` so its index is never
2026-10-15 14:51:52 -07:00
reused: walk children with `kidsOf`. A holding that moves becomes an org: its old root stays in `keys.roots` so old
keys still resolve (`money.js` keyAt), and graduation roots are kept by graduation event (`keys.adopted`), since a
node can graduate, move and graduate again. Inscription metadata is public and permanent, so never put a secret in it
(item notes included), and a charter carries a hash of the filings, never the filings.
- Charters (`src/orgchain/lineage.js`): legal form is an attribute of a node, and whether a charter stands is derived
from the tree (`standing`), never stored, so charters commute with graduations and closes.
- Keys follow the tree (`src/orgchain/keys.js`): store roots only (one per holding, one per graduated org) and derive
every other key from its position. Every act is signed by whichever key holds the authorizing inscription.
- A node's chain key is its account's BIP-86 Taproot key (`m/86'/1'/account'/0/0`); SegWit is BIP-84 at the same
account and holds its money; its Ethereum key is BIP-44 at `m/44'/60'/account'/0/0` (an org's, at account 0, is the
key tree page's legal-control key, and `tests/keyring.test.js` pins that page's vector). Leaves are HKDF-SHA256
(salt `lineage/v0`) and must stay byte for byte with lineage's key tree page; `tests/keys.test.js` holds values read
off that page.
- Keyrings (`src/orgchain/keyring.js`): every key signs the statement with its own chain's message standard (BIP-322,
EIP-191, a NIP-01 event), so real wallets can make and check the proofs. Keep those formats exact and their pinned
vectors passing; a new chain's key joins only with its own standard and a vector to pin.
- Secrets show only behind Reveal, reset on every selection, and match the key tree page byte for byte (the tests pin
hashes of the page's own output).
- The page makes no network requests; keep it that way (the deployed CSP sets `connect-src 'none'`).
- Before shipping: `npm test`, `npm run build`, `npm run test:e2e`.