DRAFT 0.3.0 · definitions of the BSA kinds are a draft (round 5); two pilot circles run on test infrastructure · last checked 27 Oct 2026
On this page

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 in transactions (SQLite on the server); Common Good is system:common-good, fed by the wave-growth counter-bookings (growWaveFromIncoming, kind step), 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 rule entry 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] (the tzdata version 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 in docs/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, written project:<id>; reserve (rezerva) = the keyless reserve; rate quote (ponudba tečaja) = 43919 v3; vote (glas) = a vote act, for or against (it replaced the objection, project_object, on 23 Oct 2026, E-5); Circle Heart (Srce kroga) = the former stewards (the technical names steward_* 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. decideProposal with approve is 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>|1 for each Heart member and g3|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, including project_close, member_exclude, member_readmit, account_close, own_open, param_propose and refusal_list_set; for circle_key_change three 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_nominate and steward_vote are 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 byContent and tagsRule
project_proposeany 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_declinerecipient["e", proposal id]consent required before opening (today's rule) [Proposal]; a decline during the vote ends the project and its votes
voteany member (on a project or a motion)["e", proposal id, "", "proposal"], ["vote", "for" or "against"]; an "against" carries its short public reason as contentbooked 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]
motiona Heart member["title", …], ["duration", "<s>"]; content = the proposalvoted 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_withdrawproposer["e", proposal id]before project_open (withdrawn); after it: project_return [Proposal]
project_closecurrent Heart members (k = 3 [Proposal])["e", proposal id], content = reasonafter 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].

  • rule entries vote_pass / vote_fall at the vote end, a duty [Decided 23 Oct 2026, E-5; the entries: Proposal]: passed (status passed) only with no member "against" as the newest vote and at least project_approvals (of the parameters in force at the vote end) Heart members in office "for", none by the proposer or the recipient counted; otherwise fell (final; it may be proposed again, changed). rule entry project_open (status receiving) is due at the end of the entry after which a passed project has the recipient's consent (and, for a step raise, fits under built); it is followed at once by drain(). A vote after the vote end is refused vote_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 (the grow and settled of every receipt, including pay, xin and a project_pay to a member; every grav deduct; the part of a named give above the project's room and a whole unnamed give; a step lowering) moves first to reserve, as one move inside the entry that produces it; then drain() moves the reserve on to receiving projects in the order of their project_open entries, the oldest first, each up to amount − received (rule reserve_move). The one canonical text is §3.9 of docs/knjiga-na-relejih.md; docs/upravljanje-kroga.md copies it. Every move is between two accounts, so the circle stays at 0 after every block. There is no dep [Decided 16 Oct, 6a] and no late xundo after a refund [Decided 16 Oct, 8j].
  • Payment [Decided 16 Oct, 8a]: when received = amount, a rule entry project_full, then in the same block project_pay: project wallet → recipient for the whole amount; then grow and settled as for a pay entry (wave growth), moved to the reserve and on by drain(). The recipient is a member [Open 8h, proposal].
  • Lapse: not opened within open_lapse_s (30 days by default) → rule entry project_lapse [Proposal, today's rule]. Closing and the 90-day end [Decided 16 Oct, 8e]: on the Heart's project_close after close_notice_s (72 h by default) of public notice, rule project_return (status closed); receive_lapse_s (90 days by default, by block at) after project_open with received < amount, rule project_lapse, then project_return (status lapsed; counting from project_open is a [Proposal], the project owner said "in 90 days"); both move the wallet's balance to the reserve and on by drain() (ledger document §3.9). [Proposal, not covered by 8e] the same return (status closed) when the recipient books project_decline or leave, or is excluded, while it receives, the proposer books project_withdraw while it receives, or project_pay falls due but the recipient is no longer a member.
  • Contributions: a member's 43910 booked as a give entry (replaces cg) naming a project in status receiving, or none; cover: the plus only (today's rule) [Open 8g]; at most amount − received is credited, the rest and an unnamed contribution go to the reserve [Open 8g]; a contribution to a project in any other status is refused not_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 at passes 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)) (written project:<id>), the reserve lift_x(sha256("lb-system/3|reserve|" + circle id + "|" + i)), for the first i that gives a valid point (the circle id: the event id of the circle's found act [Decided 17 Oct 2026, C5]); nobody can sign for them. common-good no 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 genesis entry, one rule entry start: origin → reserve, "100000" minor units (1,000.00; EUR, USD and GBP all have two decimals), then drain() (no project receives at genesis, so the start stays in the reserve). origin (SL »izvor«) is a keyless system account, derived like the others (role origin; docs/knjiga-na-relejih.md §3.8); its line is −100000 from block 1 and moves again only by close_wave when 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 of docs/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 names start and origin, the rule that origin moves only by start, close_wave and 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 of docs/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 and custodian_name, the dep and corr entries, 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, xin and a project_pay to a member.
  • There is no main account: 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, the pout entry and the held_out line field are removed; the monthly reserve statement act (bank statement) is removed; the name reserve now 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 fail statement 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's seq, identical for every signer:
    1. the member's own rule: x ≤ balance + wave (held_out is gone with payouts [Decided Q6]);
    2. the step rule: world_used + x ≤ step, where world_used = balance(world) and step = balance(world-step);
    3. 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_amount exact); an expired or wrong quote is refused at intake with a public rej stale_quote or bad_quote, nothing held.
  • xin, member sells outside, amount x, paid by circle P: world → member, then grow and the counter-booking as for pay, moved to the reserve and on by drain() [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 booked xout (A's at ≤ the quote's expires), with to_amount exact [Decided Q7; document "Currencies and exchange rates"]. Refused with a public rej entry 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 limit L(P). world_used may 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's xin embeds the same note id and books exactly to_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):
    • xundo on 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's expires (at most 10 minutes after signing). 7 days after xout, with neither B's xin nor 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 each roles entry in the blocks read, in office from the next height); each seal is judged with the office after its h_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's expires and no B block books that note id: xundo by 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 exactly to_amount: xdone by 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 an xdone or xundo it cannot verify itself. Nobody pays anything: xrefund and 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 by drain() like any project), except the recipient's consent, since world-step has no key [Proposal]. Its project_pay moves the wallet into world-step with no wave growth and no counter-booking (world-step has no wave), so the amount does not flow on: this project really uses up community money. Checked at project_open and at project_pay: step + s ≤ built, where built = Σ (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 that seq [Decided 15 Oct: never above what was built; the formula: Proposal]. [Open] what happens if step + s > built once the raise project is full; and an account close (E-3, also after a move, E-9 (b)) lowers built, so the step may then stand above it [Open].
  • Step lower, amount s [Proposal]: step_propose with a negative amount (−s) → decided by a vote like a project (§3) → rule entry step_lower: world-step → reserve, then drain(), only if step − s ≥ max(0, world_used). The builder does not book it in 0.3.0 (no complete rule); step_approve is 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 the member_join the new circle opens the reference's wave W from its origin into its reserve (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 its origin (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 inflated wave that 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 found act (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 as d. 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 over sha256("lb-found/3|" + found id)). A 30910 counts only if it is signed by the circle key that the ledger's mirror at its mirror_of names (at the height of a key change already the new key; for blocks it is in office from the next height), its tags without g equal that mirror, and its g names the pinned genesis digest (g = [genesis digest, the founder's signature over sha256("lb-genesis/3|" + circle id + "|" + genesis digest)], so no key can point the record at another chain); readers take the valid record with the highest mirror_of. Canonical address 30910:<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 its mirror_of names 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, pop and in office from the next block: Proposal]: act circle_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's created_at in decimal), so nobody names a key they do not hold; a pop is good for its own act only: an act is booked only within act_ttl_s of its created_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's expires; committed with at least k distinct current Heart members after change_notice_s (72 h by default) of notice from the k-th act, like signer_propose, relay_change and recovery. Refused [Proposal]: a pop that does not verify; the key already in office; the founder's, a witness's or a Heart member's key. Then a roles entry, booked by the witnesses, puts the new key in office from the next block (g3|circle_key|<hex>|<since_h>); a roles entry changes the circle key only when its proposing act is circle_key_change, and then to exactly the key it names. [Proposal] At most one roles entry per block, so mirror_of names exactly one mirror per height and a second roles entry 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 roles entry's height, and from then on only the new key signs the 30910; a 30910 by the old key with a mirror_of at 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 block h_to, the newest mirror at or below h_to (the genesis mirror or the newest roles entry's); its witnesses sign it, and it names their set (signers) and that mirror's circle key, as the state's g3 lines at h_to do; 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 g and founder per circle id (relay/ledger-write-policy.py, mode root, 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's found act (a 43916 whose first tag is ["c", ""] and that has no other c tag, from any author: its id is the circle id, so nobody can make a false one; the plugin remembers at most seen_ids_max found 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's founder is 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. retired entries 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_s after 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's at + max(change_notice_s, the old value of every changed parameter in seconds) [Proposal]); there is no world rules record, no rules authority and no rules_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_s 259,200 (the shortest vote, 72 h), close_notice_s 259,200 (72 h before project_return), receive_lapse_s 7,776,000 (90 days), open_lapse_s 2,592,000 (30 days; the rule is a proposal), xcheck_s 604,800 (the 7-day check of 8j), quote_ttl_s 600 and note_ttl_s 600 (10 minutes), project_approvals 3 (never below 3), act_ttl_s 604,800 and rej_per_author_per_day 20 (C3), change_notice_s 259,200 (72 h). The bounds keep a change from emptying a safeguard (for example vote_min_s at least one day, project_approvals at 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_approvals Heart "for", the proposer's and the recipient's never counted; a vote after the vote end is refused; a newer vote replaces the older; a project_propose with a duration outside vote_min_s…vote_max_s is 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 within open_lapse_s lapses; no amount, daily or open-proposal limit refuses a project [Decided 8b]; at project_open the reserve_move moves 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 by drain() [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_return moves a receiving project's balance to the reserve after a project_close with close_notice_s of notice and after receive_lapse_s without 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; no project_approve, project_object, project_answer or project_reject act and no status stopped or rejected exist [Decided E-5, C4].
  • No money in or out: no deposit or payout act type, no dep, corr or pout entry, no custodian role and no held_out field exist; a schema test proves no act, entry or setting can carry bank data.
  • World and step: a purchase outside that would bring world_used above step is refused even when the member has capacity, while at home the same member can still pay; a sale outside lowers world_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 above L(P) is refused; a hanging payment returns to the payer only when B's seals cover the time up to the note's expires and 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]; no xrefund entry exists; an expired quote is refused by A at intake and nothing is held; xdone only for a xin with the same note id and exact to_amount; an undo changes no wave and makes no counter-booking; a step-raise project pays world-step with no wave growth, and does not open if it would bring the step above built [Decided 8j]; lowering below world_used is refused; three round trips between two members leave built unchanged; world and world-step never 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]: a circle_key_change whose pop does not verify (also a pop over another act's created_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 a roles entry whose proposing act is circle_key_change, with k Heart members after change_notice_s, to exactly its key, from the next block; a 30910 by the old key with mirror_of at or above the change never counts; a second found act with the same name and code has another circle id.
  • Circle parameters [Decided E-1; the bounds and the notice end: Proposal]: a param_propose with a value outside its bounds, vote_min_s > vote_max_s or vote_max_s ≥ open_lapse_s is refused; it takes effect only by params_effective at 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 test and npm run typecheck.