Community safeguards and the step outward: technical specification DRAFT 0.3.0
Plain-words text · Technical specification · All documents
English text rendered from the project's source documents. The Slovene original is on lananostr.site. Where this text and the definitions differ, the definitions win.
Scope and status#
- Today (built, v2 as it runs): one circle per server; community orders in
support_proposals(server/support.ts); the ledger intransactions(SQLite on the server); Common Good issystem:common-good, fed by the wave-growth counter-bookings (growWaveFromIncoming, kindstep), gravity (decay.ts) and debt settlement, and an order is paid by a note signed with the fund key; objections are shown to members without the name (administrators see who); the deposit and payout routes are gone (plan step D0, 17 Oct 2026, after a copy of the live database showed no deposit and no payout). The world account and the step outward are not built. - Target (definitions 0.3.0, architecture of 16 Oct 2026, amended by the project owner's answers to questions 1–9 and to the open points, both of 16 Oct 2026, and supplemented by his answers to phase C of 17 Oct 2026, C1–C7, and by his answers before phase E of 23 Oct 2026, E-1 … E-9, which override the earlier answers where they differ): every step below is a signed act (KIND 43916) or a
ruleentry inside a circle block (KIND 43911 v3) on the circle's relays, checked by every witness (signer) before it signs. The SQLite tables become caches rebuilt from the relays. Community orders become projects with keyless wallets and a keyless reserve [Decided 16 Oct, Q8]. Everything not listed as decided is a proposal and names its question or Open label (the full rule set is in "Running a circle: witnesses and the Circle Heart"). Labels for the answers to the open points: [Decided 16 Oct, 4a / 6a / 8a / 8b / 8c / 8e / 8f / 8i / 8j / start rate source], and later the same day [Decided 16 Oct, 6c]; the answers to phase C: [Decided 17 Oct 2026, C1] to [C7]; the answers of that evening to three questions after phase D (»vsi da«; source section "Odgovori na tri vprašanja po fazi D"): [Decided 17 Oct 2026 (evening), 1A] (for now only the key that publishes the definitions signs 43920; several signatures before the first circle the project owner does not run joins; who: open; void since 23 Oct 2026, E-1), [2A] (thetzdataversion pinned at founding, part of C7) and [3A] (the transition runs per account from its first receipt); still open: [Open 8g], [Open 8h]; 8d follows from Q8; [Decided 23 Oct 2026, E-n] (with E-9 (a) and (b), answered the same day, section "Odgovora na vprašanji o referenci") and [Consequence] as indocs/upravljanje-kroga.md. - Nothing is published until definitions 0.3.0 are published and the project owner says yes (
RELAY_PUBLISH_OFF=1; one yes per definitions version and per kind switched on, P7). - Glossary (as in
docs/knjiga-na-relejih.md): witness = signer; node = proposer; act = 43916; block = 43911 v3; project (projekt) = a public plan with an amount (project_propose); project wallet (denarnica projekta) = its keyless account, writtenproject:<id>; reserve (rezerva) = the keylessreserve; rate quote (ponudba tečaja) = 43919 v3; vote (glas) = avoteact, for or against (it replaced the objection,project_object, on 23 Oct 2026, E-5); Circle Heart (Srce kroga) = the former stewards (the technical namessteward_*stay). - HEX only, never npub; the ledger never carries a person's name [Decided 16 Oct, Q5]; no bank data of any kind anywhere [Decided 16 Oct, Q6]; no deposits [Decided 16 Oct, 6a]. Amounts in minor units as base-10 strings, at most 15 digits, BigInt end to end. Labels: [M] measured 16 Oct, [C] relay config read 16 Oct, [R] earlier report, [E] estimate.
- Circle parameters [Decided 23 Oct 2026, E-1; replaces the world rules of C1]: the time values and the number of Heart "for" votes in this document (the shortest vote 72 h, 72 h before closing, 90 days, 30 days (proposal), 7 days, 10 minutes, at least 3 Heart "for") are default circle parameters, changed by the circle's Heart within the bounds of the definitions; every running deadline keeps the due time recorded when it started, never retroactive (§8).
1. Interim rules on today's tables (before the ledger log)#
decideProposal: refuse when the deciding administrator is the proposer, unconditionally ("You proposed this order; another administrator has to decide."). Today this refusal exists only under the strict policy switch, which is off by default. Keep the existing refusal when the administrator is the recipient.- Answers to objections: new table
support_objection_answers(proposal_id,objection_user_id,answered_by,note,created_at), shown to everyone under each objection.decideProposalwithapproveis refused while any objection has no answer. Rejecting by one administrator stays only in today's tables until the project acts replace them (E4c); the ledger has no rejection [Decided C4]. In definitions 0.3.0 the consensus vote replaces objections and answers [Decided 23 Oct 2026, E-5], so this interim table is not carried into the ledger [Consequence]. - Deposits and payouts are removed from the code (deposit declaration and confirmation; payout requests, confirmation,
bookPayout; their views) [Decided 16 Oct, Q6 and 6a; done 17 Oct 2026, plan step D0, after a copy of the live database showed no deposit and no payout row; the one-time step refuses to start on a ledger that has any]. - Tests: the proposer cannot approve or reject their own proposal; approval waits until every objection is answered; the answer is visible; the recipient refusal is unchanged; no deposit or payout route or table write remains.
2. The Circle Heart (technical name: stewards) [Decided 16 Oct, Q4, 4a; the name and no election: Decided 23 Oct 2026, E-2]#
- Live circle: the founder and three other Heart members (m = 4). Their HEX keys enter the log at plan step I1, not now. Governance lines in the decision state:
g3|steward:<hex>|1for each Heart member andg3|stewards_required|<k>(the technical names stay [Proposal]). - A project passes only with at least
project_approvals(3 by default, never below 3) Heart members "for" and no member "against" at the vote end; nobody decides on their own project [Decided 16 Oct, Q4, Q8, 4a; 23 Oct 2026, E-1, E-5]. [Proposal] k = 3 for the Heart's other acts, includingproject_close,member_exclude,member_readmit,account_close,own_open,param_proposeandrefusal_list_set; forcircle_key_changethree of four is decided (§7) [Decided 17 Oct 2026, C5]. - Acts:
steward_add,steward_remove,stewards_required_set(k Heart members),steward_accept,steward_resign. Members never vote on the Heart:steward_nominateandsteward_voteare removed [Decided 23 Oct 2026, E-2]. - An act has effect only once booked, and is judged by the signer's role at the booking height; votes are counted with the roles at the vote end [Proposal].
- Consequence of the decided rules (the proposer and the recipient never count, at least three Heart "for"): a project that one Heart member proposes or is paid by can pass with the other three. In a circle with fewer eligible Heart members than
project_approvals, no project can pass: it falls at its vote end, and every inflow, and the start, stays in the reserve. - Said openly (principle 3): the Heart has power the members cannot vote away; the remedy is leaving with a reference and founding another circle [Decided 23 Oct 2026, E-2 and E-9]; with an open OWN process the Heart can also hold a member's reference back [Decided 23 Oct 2026, E-9 (a)].
3. Projects as acts (safeguard 1) [Decided 16 Oct, Q8, 8a, 8b, 8e, 8f, 6c; Decided 23 Oct 2026, E-1, E-5 (replacing 8c and the objection of C4); 8d follows from Q8; Open 8g, 8h]#
Act (KIND 43916 t) | Signed by | Content and tags | Rule |
|---|---|---|---|
project_propose | any member | ["amount", minor], ["p", recipient], ["duration", "<seconds>"] (set at publication, never changed; vote_min_s ≤ duration ≤ vote_max_s) [E-5], optional ["img", sha256, url] (question 24); title and description in content, ≤ 500 characters, public for ever, inside the act (no 43925) [Decided Q5] | no maximum amount, no daily limit, no limit on open proposals [Decided 16 Oct, 8b]; vote end = its entry's at + duration |
project_consent, project_decline | recipient | ["e", proposal id] | consent required before opening (today's rule) [Proposal]; a decline during the vote ends the project and its votes |
vote | any member (on a project or a motion) | ["e", proposal id, "", "proposal"], ["vote", "for" or "against"]; an "against" carries its short public reason as content | booked only before the vote end (vote_ended); one per member per proposal, the newest counts; at the vote end the project passes only with no member "against" and at least project_approvals Heart "for", the proposer's and the recipient's not counted [Decided 23 Oct 2026, E-5] |
motion | a Heart member | ["title", …], ["duration", "<s>"]; content = the proposal | voted like a project; a passed motion is a public decision with no money effect [Decided E-5; one member and the Heart "for" count: Proposal] |
project_withdraw | proposer | ["e", proposal id] | before project_open (withdrawn); after it: project_return [Proposal] |
project_close | current Heart members (k = 3 [Proposal]) | ["e", proposal id], content = reason | after close_notice_s (72 h by default) of public notice: rule project_return moves the balance to the reserve, status closed [Decided 16 Oct, 8e; E-1] |
There is no project_approve, project_object, project_object_withdraw, project_answer or project_reject act and no status stopped or rejected: a project is decided by the vote, and a single "against" of any member makes it fall [Decided 23 Oct 2026, E-5; C4].
ruleentriesvote_pass/vote_fallat the vote end, a duty [Decided 23 Oct 2026, E-5; the entries: Proposal]: passed (statuspassed) only with no member "against" as the newest vote and at leastproject_approvals(of the parameters in force at the vote end) Heart members in office "for", none by the proposer or the recipient counted; otherwisefell(final; it may be proposed again, changed).ruleentryproject_open(statusreceiving) is due at the end of the entry after which a passed project has the recipient's consent (and, for a step raise, fits underbuilt); it is followed at once bydrain(). A vote after the vote end is refusedvote_ended; once a project receives, no vote stops it.- Inflow and
drain()[Decided Q8; order Decided 16 Oct, 8b; no project: stays in the reserve, follows from Q8]: every inflow (thegrowandsettledof every receipt, includingpay,xinand aproject_payto a member; everygravdeduct; the part of a namedgiveabove the project's room and a whole unnamedgive; a step lowering) moves first toreserve, as one move inside the entry that produces it; thendrain()moves the reserve on to receiving projects in the order of theirproject_openentries, the oldest first, each up toamount − received(rulereserve_move). The one canonical text is §3.9 ofdocs/knjiga-na-relejih.md;docs/upravljanje-kroga.mdcopies it. Every move is between two accounts, so the circle stays at 0 after every block. There is nodep[Decided 16 Oct, 6a] and no latexundoafter a refund [Decided 16 Oct, 8j]. - Payment [Decided 16 Oct, 8a]: when received = amount, a
ruleentryproject_full, then in the same blockproject_pay: project wallet → recipient for the whole amount; thengrowandsettledas for apayentry (wave growth), moved to the reserve and on bydrain(). The recipient is a member [Open 8h, proposal]. - Lapse: not opened within
open_lapse_s(30 days by default) →ruleentryproject_lapse[Proposal, today's rule]. Closing and the 90-day end [Decided 16 Oct, 8e]: on the Heart'sproject_closeafterclose_notice_s(72 h by default) of public notice,ruleproject_return(statusclosed);receive_lapse_s(90 days by default, by blockat) afterproject_openwith received < amount,ruleproject_lapse, thenproject_return(statuslapsed; counting fromproject_openis a [Proposal], the project owner said "in 90 days"); both move the wallet's balance to the reserve and on bydrain()(ledger document §3.9). [Proposal, not covered by 8e] the same return (statusclosed) when the recipient booksproject_declineorleave, or is excluded, while it receives, the proposer booksproject_withdrawwhile it receives, orproject_payfalls due but the recipient is no longer a member. - Contributions: a member's 43910 booked as a
giveentry (replacescg) naming a project in statusreceiving, or none; cover: the plus only (today's rule) [Open 8g]; at mostamount − receivedis credited, the rest and an unnamed contribution go to the reserve [Open 8g]; a contribution to a project in any other status is refusednot_receiving[Proposal]. - The money fact [Decided 16 Oct, 8f]: below the recipient's wave cap a project payment grows the recipient's wave by the whole amount and the same amount flows on, so paying a project does not shrink project wallets plus reserve; the brake on projects is the vote (at least three Heart "for", no "against") [E-5]. Exception: a step-raise project pays
world-step, which has no wave, so its amount does not flow on (§5). - Duties: a block whose
atpasses a due time starts with every due entry in canonical order; every signer refuses a block that omits one (architecture §7.4). - Keyless wallets [Decided Q8]: no wave, no cap, no gravity, no debt; a project wallet is the x-only point
lift_x(sha256("lb-system/3|project|" + <project_propose id> + "|" + circle id + "|" + i))(writtenproject:<id>), the reservelift_x(sha256("lb-system/3|reserve|" + circle id + "|" + i)), for the firstithat gives a valid point (the circle id: the event id of the circle'sfoundact [Decided 17 Oct 2026, C5]); nobody can sign for them.common-goodno longer exists. A 43910 authored by the old fund key is refused once the log is on. - The start [Decided 16 Oct, 6c: »6c, da«]: a circle's first money is one start of 1,000 in the circle's currency for the reserve at founding, and nothing else (no starting wave per member, no bridge from Lana). Block 1 books, right after its
genesisentry, oneruleentrystart:origin→reserve,"100000"minor units (1,000.00; EUR, USD and GBP all have two decimals), thendrain()(no project receives at genesis, so the start stays in the reserve).origin(SL »izvor«) is a keyless system account, derived like the others (roleorigin;docs/knjiga-na-relejih.md§3.8); its line is −100000 from block 1 and moves again only byclose_wavewhen the Heart closes an old account [Decided 23 Oct 2026, E-3] and, under E-9 (b), when a newcomer's reference wave is granted [Decided 23 Oct 2026, E-9 (b); the entry: Proposal, §3.11 ofdocs/knjiga-na-relejih.md("Membership, exclusion, the reference and closing accounts")]; it is in every snapshot and every seal (["origin", balance]), and the sum stays 0. By 8f the start keeps coming back: a project payment to a member below the cap grows that member's wave by the whole amount, and the same amount flows on as inflow to the next receiving project or the reserve. The namesstartandorigin, the rule thatoriginmoves only bystart,close_waveand the E-9 (b) grant, and the exact shape of the entry are a proposal for definitions 0.3.0 (plan C1). The live circle gets the same start in its block 1 (plan E6; proposal: 1,000 EUR ="100000"). The canonical text is §3.9 ofdocs/knjiga-na-relejih.md. - Every vote, motion and decision is a public signed event (principle 1); there is no rejection act [Decided 17 Oct 2026, C4]. The field for the reason of an "against", the purpose field and the project title and description fields warn: "public for ever; do not write names, personal or bank data" [Decided Q5].
4. No money in and no money out [Decided 16 Oct, Q6 and 6a]#
- No money in [Decided 16 Oct, 6a]:
deposit_declare,deposit_cancel,deposit_attest,deposit_reject,deposit_correct, the custodian role andcustodian_name, thedepandcorrentries, the per-attestation limit (question 12), the deposit alarm and the downward deposit correction (formerly 6b) are removed. A wave grows only with receipts:pay,xinand aproject_payto a member. - There is no
mainaccount: it stood only for money paid in (it booked deposits, their corrections and payouts; removed by plan step D0, 17 Oct 2026), and BSA has none of these [Decided 16 Oct, Q6, 6a], so it is no longer needed (the project owner also confirmed it as keyless under 8i). - No money out [Decided Q6]:
payout_request,payout_cancel,payout_sent,payout_reject, thepoutentry and theheld_outline field are removed; the monthlyreservestatement act (bank statement) is removed; the namereservenow denotes only the keyless reserve wallet. - Never on any relay, in any act or setting: bank data of any kind (account numbers, IBANs, statement files or their hashes) [Decided Q6].
- With no deposit alarm, a 43924
failstatement is public evidence and pauses nothing by itself.
5. World account and the step outward (safeguard 2, when circles connect)#
Accounts per currency, keyless system addresses [Decided 16 Oct, 8i]: world and world-step, lift_x(sha256("lb-system/3|" + role + "|" + circle id + "|" + i)); in the SQLite projection system:world and system:world-step. Excluded from gravity, wave growth and the audit's wave checks; no cap row; never in member lists (display only: they are public on the relays anyway).
Entries (each block keeps the circle's sum at 0 and carries every touched account's line after it):
xout, member buys outside, amount x: payer →world, held. Checked at this entry'sseq, identical for every signer:- the member's own rule:
x ≤ balance + wave(held_outis gone with payouts [Decided Q6]); - the step rule:
world_used + x ≤ step, whereworld_used = balance(world)andstep = balance(world-step); - across currencies, B's quote exactly as B will check it (signed by B's node of that time, B's source, not expired at this
at,to_amountexact); an expired or wrong quote is refused at intake with a publicrejstale_quoteorbad_quote, nothing held.
- the member's own rule:
xin, member sells outside, amount x, paid by circle P:world→ member, thengrowand the counter-booking as forpay, moved to the reserve and on bydrain()[Decided Q8]. No step limit. B checks A's quorum against A's signer set (from A's log, cached ≤ 24 h), that the receiver is B's member, and, across currencies, that the payment carries both amounts and the id of B's own 43919 rate quote, still valid when A bookedxout(A'sat≤ the quote'sexpires), withto_amountexact [Decided Q7; document "Currencies and exchange rates"]. Refused with a publicrejentry and its reason if P is on this circle's refusal list (refusal_list_set, k Heart members), and, only if P5 is accepted, if net sales to P (sales to P minus purchases from P) would exceed this circle's limitL(P).world_usedmay go below 0, which frees room for purchases.xdone: A makes the hold final, naming B's block by its height and digest, only if B'sxinembeds the same note id and books exactlyto_amount; anything else counts as a refusal (xundo).- Undo is a reversal, never a receipt: no wave growth, no counter-booking. A timeout alone never undoes (today's rule, kept):
xundoon B's signed refusal or "expired":world→ payer;- a payment that hangs [Decided 16 Oct, 8j]: B may book the note only in a block whose
at≤ the note'sexpires(at most 10 minutes after signing). 7 days afterxout, with neither B'sxinnor B's refusal or "expired" seen, every signer of A reads B's log from B's relays (B's signer set from B's log, cached ≤ 24 h). [Proposal] B's office is taken from B's log (the office below the lowest block read, then eachrolesentry in the blocks read, in office from the next height); each seal is judged with the office after itsh_to. A block counts only with a valid quorum of B's witnesses in office at its height: a block or seal copy without one (for example one signed only by old, retired or stolen keys that are no quorum of the witnesses in office at that height) is not B's, never counts and never hides a copy that has one; two blocks with valid quorums at one height are a fork, and the evidence is not used; what rests on an office that a missing block leaves unknown is unverifiable. So a hold whose evidence spans a key or witness change in B can still be settled, and noise signed by keys that are no quorum of the witnesses in office at that height cannot stall it; but a key that was in office at a height (for example the single witness of a one-witness circle, later stolen) can still fork that height, and a fork stops the evidence. (a) If B's quorum-signed day seals (43917) cover the whole time up to the note'sexpiresand no B block books that note id:xundoby rule,world→ payer, naming as evidence B's seals (by day and digest) and the height range read. (b) If a B block books it with exactlyto_amount:xdoneby rule, naming B's block. (c) If B's log cannot be read in full, or its seals do not yet cover that time: nothing is booked, the amount stays held and the check repeats [Proposal: every day after the morning]; never a guess, and A's other bookings go on. The check becomes a due entry only once the node has read the evidence; a witness refuses anxdoneorxundoit cannot verify itself. Nobody pays anything:xrefundand its source are removed. Since the note has expired, B cannot validly book it later, so the payer gets x back at most once. The full rule is in the ledger document (§4.5).
- Step raise, amount s [Decided 16 Oct, 8j: a project]: its recipient is
world-step[Proposal], under every project rule of §3 (the vote: at least 72 h by default, no "against", at least 3 Heart "for", the proposer never counted; filled bydrain()like any project), except the recipient's consent, sinceworld-stephas no key [Proposal]. Itsproject_paymoves the wallet intoworld-stepwith no wave growth and no counter-booking (world-stephas no wave), so the amount does not flow on: this project really uses up community money. Checked atproject_openand atproject_pay:step + s ≤ built, wherebuilt= Σ (balance + wave) over every account line that is not a system account or a project wallet, of any status, members who left and excluded members included, since their money is still in the circle [clarification, 17 Oct 2026 (D1 review)], in that currency at thatseq[Decided 15 Oct: never above what was built; the formula: Proposal]. [Open] what happens ifstep + s > builtonce the raise project is full; and an account close (E-3, also after a move, E-9 (b)) lowersbuilt, so the step may then stand above it [Open]. - Step lower, amount s [Proposal]:
step_proposewith a negative amount (−s) → decided by a vote like a project (§3) →ruleentrystep_lower:world-step→reserve, thendrain(), only ifstep − s ≥ max(0, world_used). The builder does not book it in 0.3.0 (no complete rule);step_approveis removed [Decided 23 Oct 2026, E-5]. - Reference wave [Decided 23 Oct 2026, E-9 (b); the entries: Proposal, §3.11 of
docs/knjiga-na-relejih.md("Membership, exclusion, the reference and closing accounts")]: at themember_jointhe new circle opens the reference's wave W from itsorigininto itsreserve(the grant) and pays it to the old circle's community as a cross-circle hold (reference_out/reference_in); the old circle returns exactly W to itsorigin(close_wave) and closes the account (a plus left over stays, without a wave); across currencies G = ceil(W × r_new / r_old) under the old circle's 43919. A dishonest circle can issue a reference with an inflatedwavethat its own (possibly single) witness signs, and the new circle's check of the old circle's blocks cannot see that. [Proposal, safety] The grant counts against the new circle's step outward (world_used + G ≤ step); a join whose grant does not fit waits on the waiting list, so false references cost a circle at most its own step outward (safeguard 2) [open question for the project owner: a circle that cannot raise its step takes in no waves; a founder's join in a new circle, step 0, waits too].
built is not inflated by round trips: a payment changes the payer by −x and the receiver by +x (wave), so the sum is unchanged; only project payments to member recipients and sales outside (xin, which grows the receiver's wave) raise it, and, under E-9 (b), a newcomer's reference wave [Consequence]. An undo only restores what the purchase outside lowered.
No gravity in the world accounts. Gravity on world would move the circle's purchases into its own projects and reserve and reward buying outside.
What other circles read: the whole ledger. The 43917 v3 Day Seal carries ["world", cur, used, step, built] per currency; any reader recomputes the same numbers from the blocks. GET /api/circle/summary stays only as a convenience and is never authoritative. Each circle republishes to its own relays the partner's block it relied on, so it restores without the partner; for an 8j return it also republishes the partner's seals it relied on.
Volume [E]: at the 10 October simulation's ~31 % cross-circle share [R], a payment is on average 1.62 entries and ~45 % more bytes (architecture §9).
Open in the definitions (to fix before 0.3.0): a raise uses the project acts [Decided 16 Oct, 8j], and the 7-day refund decision is gone [Decided 16 Oct, 8j], so no refund act is needed. A lowering is decided by the vote like a project (a vote naming the step_propose) [Decided 23 Oct 2026, E-5]; there is no objection, answer or step_approve any more; the rule entry that books it (step_lower) is not complete in 0.3.0.
6. Single witness [Decided 16 Oct, Q3]#
While a circle has one witness (n = 1), its "final" rests on one machine. Defences: the public label "one witness · not yet decentralised"; no money cap [Decided Q3]; the daily restore drill and any independent verifier; apps confirm that exactly one block exists at their height on 2 relays. There is no deposit alarm, because there are no deposits [Decided 16 Oct, 6a]. Other circles' exposure is bounded by the step outward in every mode.
7. A stolen or lost circle key [Decided 17 Oct 2026, C5 and C6; shapes: proposal]#
- The circle id [Decided C5]: a circle is named by the NIP-01 event id of its
foundact (43916,t=found), signed by the founder. The found act cannot carry its own id, so its first tag is["c", ""]; every other BSA event names its circle by["c", <circle id>](a payment note by["c", <circle id>, "", "from" | "to"]); the 30910 and the 30915 carry it asd. It is a fingerprint, not a key: nobody can steal it, and another found act is another circle, so a thief cannot found a false circle under the same name. The trust anchor is the circle id together with the genesis digest: a circle link or QR carries the circle id, at least two relay hints and the genesis digest as an extra pin (what the link carries: Proposal, Q10), and a reader accepts a chain only if its block 1 embeds the found act whose id is the circle id and its digest is the pinned genesis. - What the circle key stamps [Proposal]: only the 30910 mirror and, once, the found act's binding in block 1 (
circle_sig, its signature oversha256("lb-found/3|" + found id)). A 30910 counts only if it is signed by the circle key that the ledger's mirror at itsmirror_ofnames (at the height of a key change already the new key; for blocks it is in office from the next height), its tags withoutgequal that mirror, and itsgnames the pinned genesis digest (g= [genesis digest, the founder's signature oversha256("lb-genesis/3|" + circle id + "|" + genesis digest)], so no key can point the record at another chain); readers take the valid record with the highestmirror_of. Canonical address30910:<circle key in office>:<circle id>; readers query#d= circle id. Said openly: anyone can publish a 30910 naming a circle id; it counts only when the ledger's mirror at itsmirror_ofnames its author. Readers take the witness set from the ledger, never from the newest 30910. - Replacement [Decided C5: k Heart members, three of four in the live circle, public notice, booked by the witnesses; the notice
change_notice_s, 72 h by default: Decided 23 Oct 2026, E-1; the act shape,popand in office from the next block: Proposal]: actcircle_key_change(group Roles, signed by a current Heart member, text optional) with tags["key", <new key HEX>]and["pop", <the new key's BIP-340 signature over sha256("lb-circle-key/3|" + circle id + "|" + new key HEX + "|" + created_at)>](the act'screated_atin decimal), so nobody names a key they do not hold; a pop is good for its own act only: an act is booked only withinact_ttl_sof itscreated_at, so an old pop can never be used again. Endorsement form: each further Heart member signs the same type with only["e", <first act id>, "", "proposal"], booked before the first act'sexpires; committed with at least k distinct current Heart members afterchange_notice_s(72 h by default) of notice from the k-th act, likesigner_propose,relay_changeandrecovery. Refused [Proposal]: apopthat does not verify; the key already in office; the founder's, a witness's or a Heart member's key. Then arolesentry, booked by the witnesses, puts the new key in office from the next block (g3|circle_key|<hex>|<since_h>); arolesentry changes the circle key only when its proposing act iscircle_key_change, and then to exactly the key it names. [Proposal] At most onerolesentry per block, somirror_ofnames exactly one mirror per height and a secondrolesentry can never undo what the first put in office (for example a circle key change). The circle id never changes. - After the change: the new key already signs the 30910 of the
rolesentry's height, and from then on only the new key signs the 30910; a 30910 by the old key with amirror_ofat or above the change never counts. Every 43917 seal and every 30915 head names the circle key (["circle_key", <hex>], under the witnesses' quorum) [Proposal], so a reader of the root directory picks the 30910 by that key: a seal is judged with the office after its last blockh_to, the newest mirror at or belowh_to(the genesis mirror or the newestrolesentry's); its witnesses sign it, and it names their set (signers) and that mirror's circle key, as the state'sg3lines ath_todo; at the height of a key change that is already the new key; the 30915 head copies it. A lost key is replaced the same way. - First-seen rule [Decided C6]: root relays keep the first-seen
gandfounderper circle id (relay/ledger-write-policy.py, moderoot, which also checks the founder's signature over the circle id); a request in the letter to the Lana relay owner (plan phase G), now only extra safety. [Proposal] Root relays keep every circle'sfoundact (a 43916 whose first tag is["c", ""]and that has no otherctag, from any author: its id is the circle id, so nobody can make a false one; the plugin remembers at mostseen_ids_maxfound acts, and beyond it a newer circle's records are kept unpinned, never falsely pinned); a root relay pins a circle id's genesis digest and founder only when it holds that found act and the record'sfounderis the found act's author (or, for a circle configured on the relay, when its configured circle key signed the record; otherwise the record is stored unpinned; readers check it anyway), and only after every plugin of the relay (the chain) accepted the record, so nobody can claim a circle id first; a record naming another founder than the found act's author is refused.retiredentries carry their role ({"key": <HEX>, "until": <unix>, "role": "signer" | "node" | "circle_key"}): a retired circle key can sign only an old 30910, never a block, seal, chunk, head or quote. - Until the change is booked (at least
change_notice_safter the k-th act), a thief can sign 30910 records with the key in office; each counts only if it equals the ledger's mirror, so it changes nothing. A block signed only by the stolen key, or by any key without a valid witness quorum, counts nowhere, the 8j evidence included (§5) [Proposal].
8. Circle parameters instead of world rules (KIND 43920 retired) [Decided 23 Oct 2026, E-1]#
- Every time value and limit this document uses is a circle parameter with a default, changed by the circle's Heart within the bounds of the definitions (
param_propose, k Heart members, notice end = the k-th act'sat+ max(change_notice_s, the old value of every changed parameter in seconds) [Proposal]); there is no world rules record, no rules authority and norules_adopt; 43920 is retired and its number reserved. The full table and rules:docs/upravljanje-kroga.md, "Circle parameters". - The defaults this document uses:
vote_min_s259,200 (the shortest vote, 72 h),close_notice_s259,200 (72 h beforeproject_return),receive_lapse_s7,776,000 (90 days),open_lapse_s2,592,000 (30 days; the rule is a proposal),xcheck_s604,800 (the 7-day check of 8j),quote_ttl_s600 andnote_ttl_s600 (10 minutes),project_approvals3 (never below 3),act_ttl_s604,800 andrej_per_author_per_day20 (C3),change_notice_s259,200 (72 h). The bounds keep a change from emptying a safeguard (for examplevote_min_sat least one day,project_approvalsat least 3) [the bounds: Proposal]. - Fixed for every circle: a project needs at least 3 Heart "for" votes and no "against"; the money and gravity computation [Decided 23 Oct 2026, E-1].
- Never retroactive: every running deadline is recorded as a due time when it starts and keeps it (a project opened under a 90-day receive lapse keeps 90 days when the Heart later sets 30); during a parameter change's notice apps sign with the stricter value [Proposal].
- Said openly: the world-wide key of C1 and 1A is gone, and with it that tension with principle 3; the new risk is inside a circle, where the Heart can shorten its own periods within the bounds, and a shortening applies only after the period it replaces [Proposal].
Tests#
- Interim: the proposer cannot approve or reject their own proposal; approval waits until every objection is answered; answers are visible to everyone; the recipient refusal is unchanged; the deposit and payout paths are gone.
- Projects in the log: a project passes only with no member "against" as the newest vote at the vote end and at least
project_approvalsHeart "for", the proposer's and the recipient's never counted; a vote after the vote end is refused; a newer vote replaces the older; aproject_proposewith a duration outsidevote_min_s…vote_max_sis refused; with four Heart members a project proposed by or paying one of them passes with the other three [Decided 4a, E-5]; a project not opened withinopen_lapse_slapses; no amount, daily or open-proposal limit refuses a project [Decided 8b]; atproject_openthereserve_movemoves min(reserve, amount − received); a project wallet never exceeds its amount; surplus goes to the next receiving project, the oldest first, then to the reserve [Decided 8b]; with no receiving project every inflow goes to the reserve [follows from Q8]; a full project pays its recipient once and only when received = amount, and the recipient's counter-booking goes to the reserve and on bydrain()[Decided 8a, 8f]; after every entry outside the morning the reserve is above 0 only if no receiving project has room; a contribution above the giver's plus is refused [Open 8g];project_returnmoves a receiving project's balance to the reserve after aproject_closewithclose_notice_sof notice and afterreceive_lapse_swithout filling [Decided 8e]; a 43910 from the old fund key is refused; every vote carries the voter's pubkey and no act carries a name; noproject_approve,project_object,project_answerorproject_rejectact and no statusstoppedorrejectedexist [Decided E-5, C4]. - No money in or out: no deposit or payout act type, no
dep,corrorpoutentry, no custodian role and noheld_outfield exist; a schema test proves no act, entry or setting can carry bank data. - World and step: a purchase outside that would bring
world_usedabovestepis refused even when the member has capacity, while at home the same member can still pay; a sale outside lowersworld_used, lets the next purchase through, and routes its counter-booking to a receiving project or the reserve; (only if P5 is accepted) a sale that would bring net sales to P aboveL(P)is refused; a hanging payment returns to the payer only when B's seals cover the time up to the note'sexpiresand no B block books it, stands when B booked it, and stays held while B's log cannot be read [Decided 8j]; a B block without a valid quorum of B's witnesses in office at its height (for example signed only by a stolen key) is ignored, and two B blocks with valid quorums at one height stop the evidence [Proposal]; noxrefundentry exists; an expired quote is refused by A at intake and nothing is held;xdoneonly for axinwith the same note id and exactto_amount; an undo changes no wave and makes no counter-booking; a step-raise project paysworld-stepwith no wave growth, and does not open if it would bring the step abovebuilt[Decided 8j]; lowering belowworld_usedis refused; three round trips between two members leavebuiltunchanged;worldandworld-stepnever receive gravity and no key can sign for them [Decided 8i]; every block keeps the circle at 0. - Restore: replaying the blocks from the relays gives the same world numbers, project wallets and reserve as the seal.
- Circle key [Decided C5;
pop, the key-separation rule and in office from the next block: Proposal]: acircle_key_changewhosepopdoes not verify (also apopover another act'screated_at), or that names the key in office or the founder's, a witness's or a Heart member's key, is refused; the circle key changes only by arolesentry whose proposing act iscircle_key_change, with k Heart members afterchange_notice_s, to exactly its key, from the next block; a 30910 by the old key withmirror_ofat or above the change never counts; a secondfoundact with the same name and code has another circle id. - Circle parameters [Decided E-1; the bounds and the notice end: Proposal]: a
param_proposewith a value outside its bounds,vote_min_s>vote_max_sorvote_max_s≥open_lapse_sis refused; it takes effect only byparams_effectiveat its notice end, never earlier; every check of a block uses the parameters in force for it, except a running deadline, which keeps its recorded due time (a project opened under a 90-day receive lapse keeps 90 days when the Heart later sets 30); no 43920 exists. - Existing tests stay green:
npm testandnpm run typecheck.