A new circle: circle in a box: 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.
Precedence: where this document and definitions 0.3.0 differ, the definitions (docs/bsa-records-0.3.0.json) win; the difference is a bug to fix in this document. The definitions pin a frozen copy of this text (docs/0.3.0/) by its sha256 (meta.normative_spec); this living text may change afterwards, and a change reaches the definitions only when they are generated again, which then needs a new yes.
Status#
- Built and deployed (M4a, 16 Oct 2026): the settings, the locks, the clone compose file, the data volume and the tests below; the live circle is unchanged by them. Publishing is off (
RELAY_PUBLISH_OFF=1); nothing has been sent to any relay. - Decided 16 Oct 2026 (the project owner's answers to Q1–Q9; source
_reports/2026-10-16-knjiga-na-relejih/odlocitve-2026-10-16.mdin the LanaDev workspace, outside this repository): Q1 finality; Q2 the box relay and ≥ 4 relays at ≥ 3 operators, 38888 = root only; Q3 witnesses, at most one per operator, no money cap; Q4 the people who decide in the live circle (since 23 Oct 2026 the Circle Heart, E-2), a project approved by three; Q5 the ledger knows people only by HEX key, no 43925, no legal-review gate; Q6 no bank data and no payouts; Q7 rate quotes by the receiving circle's node; Q8 keyless project wallets and a keyless reserve; Q9 founding by a relay-checked rule, P3 dropped (its "at most three circles per founder" replaced by E-8, 23 Oct 2026). None of this is built, except the removal of payouts and deposits (Q6 and 6a, plan step D0). - Decided in the afternoon of 16 Oct 2026 (the project owner's answers to the open points; same source file): 4a four in the live circle (since 23 Oct 2026 the Circle Heart, E-2), the founder and three other Heart members, a project approved by three of the four (since 23 Oct 2026 the circle parameter
project_approvals, at least 3, and no "against", E-1 and E-5); 6a no money deposits (no deposit acts, nodeporcorrentry, no custodian, nomainrole, nopaid_in, no question 12, no 6b, no deposit alarm; a wave grows only from receipts); 8a a project pays its recipient the whole amount once full; 8b inflow in order of opening, no amount cap and no other limits for now; 8c an objection only within 72 h of publication, a stop lifted only by the objector's withdrawal, no stop once receiving (replaced on 23 Oct 2026 by the consensus vote, E-5); 8eproject_closeby the Heart afterclose_notice_s(72 h by default) of public notice, money to the reserve, and a project not full within 90 days ends by itself; 8f a project payment does not use up community money, the brake is the vote (E-5); 8iworldandworld-stepkeyless (mainwent with 6a); the start rate sourceecb-daily, the source date always shown, a quote valid 600 s (since 23 Oct 2026 the circle parameterquote_ttl_s, E-1); 8j a hanging cross-circle payment is paid by nobody (after 7 days the payer's circle reads the receiving circle's ledger: not booked with the seals covering the note'sexpires→ back to the payer; booked → stands; unreadable → wait;xrefundgoes), and raising the step outward is a project. 8d follows from Q8 (no receiving project → the inflow stays in the reserve). Decided later the same day (»6c, da«; same source file, section "Odgovor na 6c"): 6c one start of 1,000 in the circle's currency for the reserve at founding, booked in block 1 from the keylessorigin(the namesstartandoriginand the entry shape: proposal, plan C1); no other first money. Still open: 3a, 8g, 8h. - Decided 17 Oct 2026 (the project owner's answers to phase C; same source file, sections "Odgovori na fazo C" and "Odgovor na pojasnilo točk 5 in 1"; carried by the supplement to definitions 0.3.0 of the same day): C1 the time values and the number of project approvals are world rule values, the same for every circle, in one world-wide record, KIND 43920 BSA Rules, signed by the rules authority (the key that publishes the definitions on lananostr.site), effective at least 7 days after it is signed, never retroactively, and every block and seal names the rules version it used (replaced on 23 Oct 2026 by E-1: circle parameters, 43920 retired); C2 payments never wait for the morning (visit before touch); C3 refusals of keys that are neither members nor applicants are answered and never booked, an act is valid 7 days (now the circle parameter
act_ttl_s), at most 20 refusals of one key a day are booked (nowrej_per_author_per_day); C4 nobody rejects a project alone (project_rejectand the project statusrejectedare gone), an objection stops a project (the objection replaced on 23 Oct 2026 by the vote, E-5); C5 the circle's name is its circle id (the id of thefoundact the founder signs), and the circle key can be replaced (circle_key_change: k Heart members, public notice,change_notice_ssince E-1, 72 h by default, booked by the witnesses); C6 the first-seen rule goes into the letter to the Lana relay owner (plan phase G) and is now only extra safety; C7 the time zone, the morning hour and tzdata are fixed at founding and do not change in 0.3.0. None of this is built in the running app. - Decided the evening of 17 Oct 2026 (the project owner's answers to three questions after phase D, »vsi da« to the proposal »1A, 2A, 3A«; same source file, section "Odgovori na tri vprašanja po fazi D"): 1A for now only the rules authority's one key (the key that publishes the definitions) signs 43920; several signatures (for example 3 of 5) come before the first circle the project owner does not run joins (for example the first circle from another ecosystem); who the signers are stays open; the tension with principle 3 is thereby limited in time and said openly (1A is void since 23 Oct 2026, E-1); 2A the
tzdatapart of C7: the version is pinned in thefoundact withtzand the morning hour, and every witness computes the boundaries with it, never with a newer one of its own; in 0.3.0 it never changes, not even by the Heart; how the Heart could later move a circle to a newer version is for a later definitions version; 3A the transition (transition_days, 60 days) runs per account from its own first receipt, as the definitions say; today's app counts from the circle's start (the live circle has no payments), and the switch to the 0.3.0 gravity (plan step E4d) applies the per-account rule. None of this changes the running app. - Decided 23 Oct 2026 (the project owner's answers before phase E; same source file, section "Odgovori pred fazo E" with its "Dopolnitev" and "Referenca"; the full text is in
docs/upravljanje-kroga.md): E-1 every time value and limit is a circle parameter with a default, changed by the circle's Heart within the bounds of the definitions; no world rules record (43920 retired, its number reserved), no rules authority; fixed for every circle: at least 3 Heart "for" and no "against" for a project, the money and gravity computation; 72 h is fixed nowhere; E-2 the stewards are the Circle Heart (a Heart member), never elected by members, the Heart adds and removes Heart members (k = 3, proposal); E-3 exclusion by the Heart (three votes, at once, 3 months, readmission by the Heart as a member only), the excluded account's money rules, closing old accounts (the wave back toorigin; a minus covered only on a death); E-4 the Heart leads and oversees the circle's OWN processes, only decisions reach the ledger; E-5 the consensus vote "all for, or it falls" (the proposer sets the duration, the shortest 72 h by default) replaces approval after notice and objections (8c, C4); E-6 open / invite only / a maximum with a waiting list; E-7 witnesses by lot among the circles' computers (the direction for phase I), one witness until then, the Heart's vote only for exceptions; E-8 only a member of an existing circle founds, one circle per founder key, one circle per person at a time (replaces "at most three circles per founder"); E-9 the reference (43921: a proposal for the number): issued by itself after "I want to leave" when the conditions hold; nobody moves without it. The same day (section "Odgovora na vprašanji o referenci"): E-9 (a) an open OWN process blocks a reference also without a debt; E-9 (b) the new circle opens the same step, sends the same amount to the old circle's community, and the old circle closes the account and returns the amount to itsorigin(it cancels out; the entries: Proposal, §3.11 ofdocs/knjiga-na-relejih.md; the grant counting against the step outward: Proposal, open question for the project owner). None of this is built in the running app. - Not built, proposals unless marked: everything under "Target". Each item names its number among the 24 questions for the project owner of 16 Oct 2026; the numbers come from the architecture study of the same day. Labels: [M] measured 16 Oct, [C] relay config read 16 Oct, [R] earlier report, [E] estimate; since 23 Oct 2026 also [Decided 23 Oct 2026, E-n], [Proposal] and [Consequence].
- Glossary (as in
docs/knjiga-na-relejih.md): witness = signer; node = the witness that proposes and orders blocks (the proposer); majority of witnesses = quorum q of n (3 of 4); Circle Heart = k of m Heart members (formerly the stewards; the technical namessteward_*stay); act = 43916; block = 43911 v3; daily seal = 43917 v3; circle record (mirror) = 30910 v3; member home = 30916 v3; project = a published purpose with an amount that the circle funds (project_*acts), decided by a consensus vote; vote = a signedvoteact, "for" or "against" (an "against" with a short public reason); motion = any other proposal a Heart member puts to a vote; project wallet = the project's keyless account; reserve = the circle's keyless account for surplus; rate quote = 43919 v3, signed by the receiving circle's node; found act = thefoundact (43916) the founder signs (SL »ustanovna listina«); circle id = the event id of the circle's signedfoundact, its name for ever (SL »rojstna številka kroga«); parent circle = the circle a found act names (SL »matični krog«); genesis digest = the digest of block 1 (SL »prstni odtis prvega bloka«); circle key = the key that stamps the 30910 mirror, replaceable bycircle_key_change; circle parameters = the integer settings of a circle (docs/upravljanje-kroga.md, "Circle parameters"); reference = thereferenceentry of a member who left settled, and its findable copy 43921 (SL »referenca«); 43920 = retired (there are no world rules any more). - HEX only, never npub; amounts in minor units as base-10 strings, ≤ 15 digits, BigInt.
Settings (built)#
| Variable | Rule | Live circle |
|---|---|---|
CIRCLE_CODE | ^[a-z0-9][a-z0-9-]{2,23}$, the 30910 d | dance2abundance-v2 |
CIRCLE_NAME | 1–80 characters, one line | Dance2Abundance |
CIRCLE_CURRENCY | exactly one of EUR, USD, GBP | EUR |
APP_ORIGIN | https page address, no trailing slash | https://one.letsbalance.life |
ADMIN_PUBKEYS | creator's BSA ID (Nostr HEX), comma-separated | the project owner's |
server/shared/circleConfig.tsparses the three circle settings; an empty value takes the live circle's, a wrong value stops the start. The server reads the environment; the page gets the same values at build time (vite.config.tsdefine), and the build writes them todist/circle.json.server/main.ts(the process entry) runsserver/circleCheck.tsbefore anything else: it comparesdist/circle.jsonwith the server's settings and refuses to start on any difference, beforedb.tsopens the ledger, so a refused start locks nothing. Nodist/circle.json(a laptop run, the tests): no check.db.tslocks the currency (community_currency) and the code (circle_code) at the first start; a later start with another value is refused. A database from before the code lock takes its code at the next start (the live circle: its own).- A clone without
APP_ORIGINdoes not start (circle.ts); only the live circle falls back to its own address. - The page shows the circle's unit and money word (
COMMUNITY_UNIT,COMMUNITY_MONEY_WORDinshared/features.ts); the live circle's texts are unchanged. - Newcomers get a wallet in
CIRCLE_CURRENCY; the treasury account is named<CIRCLE_NAME> Communityin a new ledger. Internal account ids (system:dance2abundance,system:common-good) are the same in every circle today. Target (decided Q8):system:common-goodis replaced by the keylessreserveand one keyless account per project (below).system:main, the counter-account of money paid in, went with deposits (decided 6a; removed by plan step D0, 17 Oct 2026), so no circle has a main account. - The circle record's description is "A LetsBalance circle: one node, one currency (<unit>)" in a clone; the live circle keeps its text byte for byte. A clone's rules link is
<APP_ORIGIN>/how-it-works. - Target:
ADMIN_PUBKEYSis used once, to recognise the founder when thefoundact is signed; afterwards the Heart members come only from the ledger (decided Q4 and 4a for the live circle: the founder and three other Heart members, m = 4; the name Circle Heart: E-2; k = 3: decided for the circle key, C5, a proposal for the Heart's other acts, kept by E-2). - Target (decided 17 Oct 2026, C5): in 0.3.0
CIRCLE_CODEis only a readable label: thefoundact carries it (["code", <code>]), the 30910 repeats it ascode, and it never changes. The circle's name, the 30910dand thectag of every other BSA event are the circle id, the id of the signedfoundact; no address is built from the code any more.
Files (built)#
circle.env.example→.env;docker-compose.circle.yml:docker compose -f docker-compose.circle.yml up -d --build. The port is bound to the loopback address (this machine only) (HOST_PORT); a reverse proxy gives https.- Today the Docker volume
letsbalance-<code>-dataholds the ledger,keys.json,seals/andseal-salt.secret(a named volume, because a host folder made by Docker belongs to root and the app user could not open its ledger). Back it up whole withdocker compose -f docker-compose.circle.yml cp web:/app/data ./backup. Until publishing is on, this backup is the only copy of the ledger. - Target: the volume holds the keys (the node's signer key, sign-guard, write-ahead log) and a cache; the ledger restores from the relays.
seal-salt.secretgoes away with the salted seal (consequence of principle 1, no new decision; plan step E2). The fund key goes (decided Q8). Dockerfile:CIRCLE_*as build arguments; the tests run with the circle settings removed; the runtime image has the same values as the page.- The live circle keeps
docker-compose.prod.ymlandscripts/deploy-on-server.sh(backup, trial start on a copy, previous image); no deploy between 04:00 and 06:00 Ljubljana. The GitHub deploy job runs only in the live repository; a clone's CI runs the checks.
Tests (built)#
server/clone.test.ts: settings rules; a clone with its own code, name and USD has an empty ledger, refuses EUR, gives newcomers a USD wallet, names itself in 30910 and 43917 and points nowhere at the live circle; a page built for another circle stops the start before any ledger exists; the code lock; no start withoutAPP_ORIGIN.server/seal.test.tstoday also checks the 20-account rule for public counts; that rule and its test are removed with the salted seal (consequence of principle 1).server/circle.test.tskeeps the live values (dance2abundance-v2).
Target: founding and genesis (proposal; constraints decided Q3, Q7, Q8, Q9, 6c, C3, C5, C6, C7, E-1, E-8, E-9)#
- Before founding [Decided 23 Oct 2026, E-8 and E-9; the shapes: proposal]: only a member of an existing circle founds. The founder books
leavein the parent circle; the parent circle's ledger books thereferenceentry by rule once the conditions hold (balance ≥ 0; no open OWN process together with a minus; no open OWN process at all [Decided 23 Oct 2026, E-9 (a)]), and the parent's node publishes the 43921 copy. A founder in minus must settle first (anyone may pay into the account, never above 0); without a reference there is no founding. The live circle is the root and needs none. The founder's built step follows them into the new circle [Consequence of E-9 (b)]: the new circle grants the same wave and pays the same amount to the parent's community, which closes the old account and returns it to itsorigin; the same transfer as every move (the grant,reference_out/reference_in,close_wave) [the entries: Proposal, §3.11 ofdocs/knjiga-na-relejih.md("Membership, exclusion, the reference and closing accounts")]; [Proposal, safety] the grant counts against the new circle's step outward, 0 at founding, so the founder's join waits until it fits (open question for the project owner). foundact (KIND 43916,t = found), signed by the founder in their browser (P2), withexpiresat mostact_ttl_safter signing (7 days by default; decided 17 Oct 2026, C3; a circle parameter since E-1). Its event id is the circle id (decided 17 Oct 2026, C5): the circle's name for ever, a fingerprint, not a key, so nobody can steal it, and anotherfoundact is another circle. It cannot carry its own id, so its first tag is["c", ""]; every other BSA event except the 30910 names the circle by["c", <circle id>](a payment note by["c", <payer circle id>, "", "from"]and, across circles,["c", <receiving circle id>, "", "to"]), and the 30910 and the 30915 carry it asd;scope16= the first 16 hex characters of the circle id. Aftercandtits tags come in this order (the shapes: proposal):["name", …],["code", <circle code>](a readable label that never changes; it is no longer part of any address),["circle_key", <HEX>](the first circle key; never the founder's, a witness's or a Heart member's key: proposal),["currency", "EUR"|"USD"|"GBP"],["tz", <IANA time zone>],["tzdata", "2026a"],["morning", "<0 to 23>"](the time zone, the morning hour and tzdata are fixed at founding and do not change in 0.3.0; decided 17 Oct 2026, C7), the first signer set["signer", hex, operator]… (n = 1: the box's node key),["quorum", "<q>", "<n>"],["proposer", hex], the first Circle Heart["steward", hex]… (the technical name stays) and["stewards_required", "<k>"], relays["relay", wss, operator]… (≥ 4 of ≥ 3 operators, decided Q2) and["archive", wss]…, an optional["bootstrap", "Q14"]label while open question 14 is not decided,["rate_source", "ecb-daily", <description>](the circle chooses its source, decided Q7),["api", <https URL of the write intake>], every circle parameter["param", name, "<integer>"]in the order ofdocs/upravljanje-kroga.md"Circle parameters" (the six wave and gravity parametersband_ppm_day,excess_ppm_day,transition_days,rest_after_days,wave_cap,w_max_s, thenvote_min_s,vote_max_s,project_approvals,close_notice_s,receive_lapse_s,open_lapse_s,change_notice_s,xcheck_s,quote_ttl_s,note_ttl_s,act_ttl_s,rej_per_author_per_day,exclusion_s,invite_ttl_s,invite_only,max_members), each in its range (decided 23 Oct 2026, E-1; the order and the bounds: proposal),invite_only0 (a new circle has no member yet who could invite the first one; a found act with 1 isbad_template, and the Heart turns it on later byparam_propose) [clarification, review of round 5, 23 Oct 2026], the start["start", "100000"](decided 6c: 1,000 in the circle's currency) for the keylessreserve(decided Q8),["parent", <parent circle id>, <parent genesis digest>]and right after it["e", <43921 id>, "", "reference"](the parent circle and the founder's reference from it; both required except for the root circle, the live circle; decided 23 Oct 2026, E-8; the reference: consequence of E-8 and E-9; the shapes: proposal) and["definitions", "0.3.0"](Q20); then, as in every act, the optionalafter,expires, the optionalidemand["v", "3"]. The found act names no world rules version any more (43920 retired, E-1). No project amount cap and no per-member limits (decided 8b). No money cap (decided Q3). No custodian, no deposit limits and nomainaccount (decided 6a).- The time values and limits are circle parameters (decided 23 Oct 2026, E-1; replaces C1 and 1A): the shortest and longest vote, the number of Heart "for" votes a project needs (never below 3), the 72 h before closing, the 90 days to fill, the 30 days to open (a proposal), the notice of a roles or parameter change (72 h), the 7 days before the 8j check, a quote valid 600 s, a note valid 600 s, an act valid 7 days, the daily limit of 20 booked refusals, the length of an exclusion and of an invitation, invite only and the maximum number of members are carried by the found act as circle parameters with defaults and changed only by the circle's Heart (
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]) within the bounds of the definitions. There is no world rules record (43920 retired, its number reserved), no rules authority and nometa.rules_authorityormeta.rule_values. Fixed for every circle: a project needs at least 3 Heart "for" votes and no "against"; the money and gravity computation. The full table, the change rule and the cross-circle rule:docs/upravljanje-kroga.md, "Circle parameters". - It becomes block 1: a KIND 43911 v3 block whose
genesisentry embeds thefoundact (rebuilt with["c", ""], because its id is the circle id), the mirror that thefoundact gives, and the signature of the circle key thefoundact names oversha256("lb-found/3|" + found id)(circle_sig), which binds that first circle key to the founding; it is followed at once by oneruleentrystart: the keylessorigin→reserve,"100000"(decided 6c; the namesstartandoriginand the entry shape: proposal, plan C1;docs/knjiga-na-relejih.md§3.9); a block 1 without it is invalid. Block 1 is booked under the parameters thefoundact carries.originis −100000 from then on and moves only byclose_wavewhen the Heart closes an old account (decided 23 Oct 2026, E-3; the mechanics: proposal), and the sum stays 0. Genesis digest = the digest of block 1 (its NIP-01 hash without the witnesses'qstags), carried on every later block (["genesis", digest]). The trust anchor is the circle id together with the genesis digest (decided 17 Oct 2026, C5 and C6). The 30910 names the founder (["founder", hex]) and the parent (["parent", …], when the found act names one) and carries ingthe genesis digest with the founder's signature oversha256("lb-genesis/3|" + circle id + "|" + genesis digest), so no key can point the record at another chain, and the directory can check decision 9 and E-8. - The circle link and QR carry the circle id, at least two relay hints and the genesis digest as an extra pin (decided 17 Oct 2026, C5; the details: proposal). A reader accepts a chain only if its block 1 embeds the
foundact whose id is the circle id and its digest is the pinned genesis (from the link, or the firstgit saw for the circle id), and never follows a 30910 with anothergor founder for that circle id (Q10). A thief cannot found a false circle under the same name: hisfoundact has another id. Said openly: anyone can publish a 30910 that names a circle id; it counts only when 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), its tags withoutgequal that mirror and itsgis the pinned genesis (below, "Target: keys"). The first-seen rule of the root relays (keep the firstgand founder per circle id;relay/ledger-write-policy.py, moderoot, which also checks the founder's signature over the circle id and, as a proposal, pins a circle id only when it holds that circle'sfoundact and the same founder signed it (or, for a circle configured on the relay, when its configured circle key signed the record); below, "Target: the box relay") is a request in the letter to the Lana relay owner (plan phase G) and is now only extra safety (decided 17 Oct 2026, C6). The circle key can be replaced (decided 17 Oct 2026, C5; below, "Target: keys"). - Directory listing (decided Q9 and E-8): the root relays list a circle only if its founder holds a wallet in the Lana registrar, the found act names a parent circle with the founder's reference (except the root), and the root relays hold no earlier found act of the same founder (one circle per founder key, ever; this replaces "at most three listed circles per founder") [decided 23 Oct 2026, E-8; the check: proposal, details phase G]; the relay checks this itself. Whether the founder was a member of the parent when founding is checked by the root directory and by readers (proposal). Said openly: one person with two keys is not prevented (that needs Lana's person check). No personal approval; seals go to the relays from the first block (P3 dropped).
- Live circle (plan E6): on a copy of the live database prove every balance, wave, carry and debt is 0 and that no order is open (payments in, payouts and
system:mainare gone from the code: plan step D0 removes their tables at the first start of the deployed code, after checking them empty; a copy of the live database was checked empty on 17 Oct 2026); Common Good's balance (expected 0) opens as the reserve (proposal), otherwise the genesis gets opening lines and the report says so; an open order would be published again as a project and lose its approvals and its 72 hours (proposal). Its block 1 books the same start (decided 6c; proposal for the live circle: 1,000 EUR,"100000"), so the reserve holds the start andorigin−100000. The founder signs thefoundact in their browser as founder; the session never sees his key. Its id becomes the live circle's circle id; it is the root circle, so it names no parent and needs no reference (decided 23 Oct 2026, E-8: every circle grows from the first one; the shape: proposal). The codedance2abundance-v2stays as the readable label; the act names a first circle key made for this in his browser (P2), never his own key (proposal). The four Heart members (the founder and three other Heart members; decided Q4 and 4a; the name: E-2) are entered with their HEX at plan step I1, not now.
Target: the box relay (decided Q2, Q9, C5, C6, E-1, E-8; proposals Q14, Q18, Q19)#
- strfry in the box compose file, with its own volume; bound to the loopback address (this machine only) until the project owner's yes (plan F3). It counts as a relay of the circle.
- Write policy (shipped with the box; the Lana relays need their owner's change):
- every BSA event except the 30910 (whose
dis the circle id) names its circle by["c", <circle id>]; the relay serves only the circles it is configured for, each by itsid(the circle id) beside itscircle_key(the key in office); a key that leaves its role (the old circle key after acircle_key_change, a witness or node key that leaves) moves toretiredas{"key": <HEX>, "until": <its last created_at, unix>, "role": "signer" | "node" | "circle_key"}, and a retired key counts only in its own role up to itsuntil: a retired circle key can sign only an old 30910, never a block, seal, chunk, head or quote (proposal), so the rules below accept a retired key only in that role and only up to itsuntil; thefoundact (["c", ""]) is accepted when its own id is a served circle id; - blocks, seals, snapshot chunks and heads (43911, 43917, 43918, 30915) accepted only from keys in the circle's current signer set, read from its log; rate quotes (43919 v3) only from the circle's node key; the circle record (30910 v3) only from the circle key in office; references (43921) only from the circle's node key (proposal); there is no 43920 any more (retired; decided 23 Oct 2026, E-1);
- 43916 and standalone 43910 only from members and applicants of that circle, rate-limited per author; 43924 statements from any author (signers, verifiers, auditors), rate-limited per author;
- [Open] the policy must also admit 43916 from keys the log names as witness or guardian who are not members (
docs/upravljanje-kroga.md); there is no custodian (decided 6a); - refuse KIND 5 and 62 that target ledger kinds or are authored by any ledger key; refuse
expirationand NIP-70-on every BSA kind; - root mode (the Lana relays): keep every circle's
foundact (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; proposal); keep the first-seeng(genesis digest) and founder of every circle id (from the circle link, or the first v3 30910 accepted, after checking the founder's signature over the circle id) and refuse a later 30910 with anothergor founder (the first-seen rule,relay/ledger-write-policy.pymoderoot: a request in the letter to the Lana relay owner, plan phase G, and now only extra safety; decided 17 Oct 2026, C6); proposal: a root relay pins a circle id'sgand founder only when it holds that circle's 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 relay stores the record unpinned, and readers check it anyway), so nobody can claim a circle id first on a root relay; keep the first found act of every founder key and refuse a second circle record of the same founder (one circle per founder key, ever; decided 23 Oct 2026, E-8; the mechanism: proposal); keep every member home (30916) and never delete one by KIND 5, since a member home names a person's last circle for the reference check (proposal, E-8 and E-9); a pin is written only after every plugin of the relay (the chain) accepted the record; pins live in the write policy'spins_file, not in LMDB, and are not rebuilt from lookback, so a relay seeded from another relay's LMDB copy also copies thatpins_file; - BSA kinds out of every purge and hard-delete filter; the box relay never deletes (Q19);
rejectEventsOlderThanSeconds = 4000000000(larger than the current unix time; measured 16 Oct 2026 on strfry 1.1.0: the value0refuses every event, even one made now) (no 10-year lower limit);- per-IP limits sized for carrier-grade NAT, per-author limits instead;
- tested before the first publish, including whether strfry refuses to re-insert an id after a KIND 5 (unverified).
- every BSA event except the 30910 (whose
- Relay list in the ledger:
relay_changeact →rolesentry; the 30910 v3 mirror carries["relay", wss, operator]× ≥ 4 and["archive", wss]… - ≥ 4 relays, ≥ 3 operators (decided Q2). Bootstrap ≥ 2 operators while the circle is borrowed is proposal Q14, a temporary departure from decision 2 that the project owner must approve; proposal: ≥ 3 operators at the latest when the circle has four witnesses (the old money-cap trigger is gone with Q3). The Lana relays count as copies only after their owner applies this policy (plan G3, letter Q18). They count as one operator until shown otherwise: NIP-11 lists four contacts [M], but the relay-owner letter is addressed to one owner and one key reaches all four hosts. [Open] (Q14, Q18): until the Lana relay owner applies the write policy, only the box relay counts, so under Q1 (decided) no block could become final and the circle would depend on one outside owner. the project owner chooses: (a) the circle books nothing until then; (b) until then the Lana relays count as copies, publicly labelled "copies without protection against deletion"; (c) until then the circle finds two more relays with the same policy at other operators.
- Borrowed quota on the Lana relays: limited space per circle (decided Q9); proposed 1 GB or one year per circle, whichever comes first.
- Publication: a single publisher (the proposer) on persistent sockets to every listed relay, pipelined in height order; signers republish what is still missing after 5 s. A daily replication audit (NIP-77 negentropy scoped by
#cand day) fills gaps and the app shows "copies N of M". Never lana-relay-sync and never the strfry router for ledger kinds. - Sizes [E]: one copy per year: 1,000 members × 2 payments a day ≈ 5 GB; 1,000 × 10 ≈ 22 GB; 100,000 × 10 ≈ 0.9 TB. A 1,000-member box needs ~20–90 GB a year for 4 copies. The Lana relays have 11 / 90 / 23 / 51 GB free [M/C]: about 2 circle-years of one 1,000-member circle at 2 a day. Disk alarm at 70 %.
- Who pays: the circle itself (Q15, proposal); under decision 8 a project of the circle, no longer an order from Common Good.
- Root relays (decided 14 Sep, scope decided Q2): only the Lana relays in the newest KIND 38888 (
relaytags only); they carry the directory (the 30910 mirror, found by#d= the circle id; the 30915 heads,d= the circle id, spread over 24 h: each published the first 4 bytes, big-endian, of sha256(the circle id as 64 hex characters) mod 86,400 seconds after its seal; KIND 0; member homes while borrowed), the member homes (30916; the newest names a person's last circle, decided 23 Oct 2026, E-8 and E-9) and, while borrowed, small circles' ledgers under the quota. Rate quotes live on the circles' relays, not on root (decided Q7). Circle relays are named by each circle in its own log; the 14 September rule applies to root relays only.
Target: witnesses (decided Q1, Q3, E-7; proposals Q17, Q23)#
- Signer set S(h): n = 3f + 1, quorum q = 2f + 1. Default n = 4, q = 3 (decided Q3); n = 7, q = 5 above about 10,000 members (proposal, Open 3a); bootstrap n = 1, q = 1 (decided Q3).
- Proposer (the node): phase 1 a fixed signer (the box); phase 2 rotating among the signers (same format; proposal).
- Each signer: its own key (file mode 600, never on a relay); a sign-guard fsync'd before every signature is released (
{circle, key, last_h, last_digest}); a write-ahead log of signed blocks not yet on 3 relays; a relay with the circle's whole history; a daily 43924 Statementokwith the state root it computed and the root over every vote it signed that day (Q23 option A). - Who the witnesses are (decided 23 Oct 2026, E-7; replaces "the circle chooses and replaces its signers itself" of Q3): witnesses are computers, chosen by lot among the circles' computers. The direction for phase I (docs only, no code in 0.3.0;
docs/releji-svetovna-mreza.md): a public random number (for example a Lana chain block), a schedule that changes regularly and is known in advance, a new witness that loads the circle from the latest seal; open: fake circles, load matching, absent witnesses. Until there are enough circles to draw from, a circle has one witness, its own computer, publicly labelled (decision 3, unchanged for 0.3.0). - Exceptions (the Heart's vote; proposed procedure):
signer_propose(the larger of k and 3 Heart members, E-10) +signer_accept(the new signer) →change_notice_s(72 h by default) public notice → committed by the current quorum, effective at a stated height, and only while no Heart member in office has "against" as the newest vote on it (decided 23 Oct 2026, E-7: "for" and no Heart "against"; E-10: at least three Heart members, the threshold is the larger of k and 3);signer_removeandsigner_replacethe same way.proposer_swap: k Heart members + current quorum, no notice.recovery(fewer than q signers survive): max(k, 3) Heart members (E-10) +change_notice_snotice, no Heart member against, void if any quorum-valid block above the named height appears during the notice; the starting height is the highest found on any relay or archive. - Rule in the log (decided Q3): at most one signer per operator (whether a seven-signer circle may allow two: Open 3a); every signer is named with its operator in the log and in the 30910 mirror.
- Finality (decided Q1): the block carries ≥ q valid signatures of S(h) and ≥ 3 listed relays answered
OK truefor this exact id and every lower height is final. The operator count of those relays (≥ 3, bootstrap ≥ 2) is Q14. Sending to the other relays continues and the payment does not wait for them (Q17, proposal); the app shows the real N of M. - Latency [E]: single signer on borrowed Lana relays ~0.5–1.5 s; own regional relays with a quorum of 3 of 4 ~0.3–0.9 s; p99 target < 3 s. EVENT→OK was never measured (plan B1 measures it on a separate strfry, never on the production relays).
- Liveness: with more than f signers down, payments wait and reads work (liveness lost, safety kept).
Target: day one with a single witness (decided Q3)#
- n = 1, q = 1. The app shows "single witness — not yet decentralised".
- No money cap (decided: "ni meje denarja"): no cap parameter in the
foundact, nothing lifted at I2; once n = 4 with four operators the label goes. - Known bootstrap weakness: if the guard is lost, a new key epoch is opened by the Heart's acts alone (no quorum exists yet).
- Defences: the public label; the daily restore drill and any independent verifier; apps confirm exactly one block at their height on 2 relays. There is no circuit breaker: the payout breaker goes with decision 6, and the proposed deposit alarm goes with decision 6a (no deposits).
Target: the daily restore drill (consequence of principles 1 and 2)#
- After the seal, the proposer (and any independent verifier) restores the circle from the relays alone into a scratch database, compares the canonical state hash with the seal's state root and writes a 43924 Statement
["about", "restore"](held until yes, then published). - A failed drill is an alarm on the admin page and a line in the app for every member ("restore check failed on <day>").
- Restore steps: find the circle (link/QR: the circle id, relay hints and the genesis digest; or root: newest 38888 → the 30915 head by
#d= the circle id, whose seal names the circle key of the newest mirror at or below itsh_to, at the height of a key change already the new key (proposal) → the 30910 by#dfrom that key); read genesis and everyrolesentry (the circle key, witnesses and Heart members in office come from them, never from a 30910); take the newest 43917 from ≥ 2 relays with a valid quorum (prefer one with ≥ 2 independentokstatements; two valid seals for one day = fork alarm, stop); fetch all 43918 chunks by#iand verify them against the seal; fetch blocks fromh_to + 1to the tip by#hfrom every listed relay (union, de-duplicated); a run that does not start at block 1 is checked with the office and the circle parameters below it, read from the ledger (the newest roles mirror and theg3|param:*lines below the run, here from the verified chunks); without them those checks are unverifiable, and so is what began before the run (an endorsement whose proposing act, arolesentry whose acts, anxdoneorxundowhose hold, aproject_openwhose project, or a refusal whose key's membership lies before it: never refused, never passed; a witness checks those against its own state below the run), and a witness never signs what it cannot verify (proposal); verify chain, quorum and every embedded signature, including every referenced rate quote, so the restore needs no root relay (there is no 43920 any more, E-1); replay; a height missing everywhere stops the restore with its number; rebuild the SQLite projection; resume with a new proposer byproposer_swaporrecovery. - Costs [E]: 1,000 members at 2 a day: snapshot 0.2 MB, one day's tail ~3,100 blocks / 7 MB, read 1–4 s; 100,000 members at 10 a day: 20 MB, ~56,000 blocks / 1.2 GB, 2–12 min.
- Tests: delete the test database → restore → identical canonical state hash; restore from seal + tail equals full replay; a hard-deleted block on one relay is found on another and republished; a block missing everywhere stops with its height.
Target: projects and the reserve (decided Q8, 4a, 8a, 8b, 8e, 8f, 8i, 8j, 6c, E-1, E-5; follows: 8d; open 8g, 8h; 8c and C4 replaced by E-5)#
The one canonical text of every project rule is §3.9 of docs/knjiga-na-relejih.md; this section is a summary that must match it word for word in its rules.
- Circle parameters (decided 23 Oct 2026, E-1; replaces C1): the times and the number of Heart "for" votes in this section are circle parameters with defaults: the shortest vote, 72 h =
vote_min_s(E-5), the longest, 14 days =vote_max_s(proposal), the 72 h before closing =close_notice_s, the 90 days to fill =receive_lapse_s, the 30 days to open =open_lapse_s(proposal), the three Heart "for" votes =project_approvals(never below 3). Every running deadline is recorded as a due time when it starts and keeps it, never retroactive: the vote end and the open lapse from the publication, the receive lapse from the opening, the closing due from the k-th close [clarification, 17 Oct 2026 (D1 review); E-1]. - Accounts:
reserveexists from genesis (named in thefoundact) and holds the start from block 1 (6c). A project wallet exists from the project's publication; it is writtenproject:<id>(id = the id of itsproject_proposeact) and derived as below ("Keyless accounts"). Both are keyless, have no wave, no cap, no gravity and no debt, and never go below 0.system:common-goodand the fund key go. - Acts (43916; names as in
docs/knjiga-na-relejih.md§3.4):project_propose(title, description, amount with no cap for now [8b], recipient: Open 8h; images: Q24;["duration", "<s>"]set at publication and never changed,vote_min_s≤ duration ≤vote_max_s[E-5]),project_consent/project_decline(recipient; as today, proposal),vote(any member, "for" or "against", an "against" with a short public reason; the newest counts, changeable until the vote end [E-5]),motion(a Heart member puts any other proposal to a vote [E-5; one member: proposal]),project_withdraw(proposer),project_close(Heart members, afterclose_notice_s, 72 h by default, of public notice [8e]; how many sign: proposal, k = 3 of 4). Removed:project_object,project_object_withdraw,project_answerandproject_approve[E-5]. There is noproject_reject(decided 17 Oct 2026, C4). Every free-text field carries the warning "public for ever; do not write names, personal or bank data" (decided Q5). - States:
proposed(voting) → at the vote endpassed(no member "against", at leastproject_approvalsHeart members "for", the proposer's and the recipient's not counted [E-5, 4a]) orfell(final; it may be proposed again, changed);passed→receivingonce the recipient consented (proposal, as today) and, for a step raise, the step fits underbuilt→fullwhen received = amount →paid[8a]. Alsodeclined,withdrawn(a decline or withdrawal during the vote ends the project and its votes; there is no statusrejected(C4) and nostopped(E-5)),lapsed(project_lapse: no opening withinopen_lapse_sof publication, today's order rule kept as proposal; or not full withinreceive_lapse_safter it opened [8e; counted from the opening: proposal], thenproject_return) andclosed(project_return: afterproject_close[8e], or, as proposal, when the recipient declines, leaves or is excluded while it receives, the proposer withdraws it while it receives, orproject_payfalls due and the recipient is no longer a member). Aclosedorlapsedreceiving project's balance moves toreserve, thendrain(). - Inflow (decided Q8; the form is the recommended design): every wave-growth counter-booking (today
growWaveFromIncoming: member → Common Good), every morning gravity line (todaydecay: member → Common Good), every settled waiting flow (todaysettleWaitingFlow) and every contribution (todaycontribute; only from the plus, Open 8g) moves first toreserve, one move per receipt as today; thendrain()moves the reserve on toreceivingprojects, never above their amounts, the oldest opening first [8b]; with no project receiving it stays in the reserve (8d, follows from Q8). No project amount cap, no one-a-day limit and no three-open limit for now [8b]: today'sSUPPORT_MAX_AMOUNTand proposal limits are not carried over. - Reserve transfer (decided): in the block in which a project enters
receiving,drain()moves min(reserve, amount − received) to it (rulereserve_move). - Payment to the recipient [8a]: when received = amount, a
ruleentry pays the whole amount to the recipient (as today'spaySupport), and the recipient's wave-growth counter-booking goes to the reserve and on bydrain(). The pay-as-it-comes alternative is not taken. - Sum (principle 4): Σ balances = 0 after every block; Σ waves = counter-bookings into the reserve − counter-bookings returned from it.
- The money fact [8f]: below the recipient's wave cap a project payment does not shrink project wallets plus reserve; the brake on projects is the vote (three Heart "for" and no "against", E-5).
- The step outward [8j]: raising the step is a project like any other: passed by the vote like any project (E-5), filled by
drain(); when full, the step rises by its amount. Proposal for the form:project_proposewith the keylessworld-stepas recipient (no consent, no doer);project_paymoves the amount toworld-step, which as a system account makes no wave growth and no counter-booking, so this payment does leave the pool. Lowering the step is not covered by the answer and stays a proposal: decided by a vote like a project, not booked in 0.3.0 (docs/upravljanje-kroga.md). The reserve no longer pays the step, and there is no refund from the reserve: a hanging cross-circle payment is settled by the 8j ledger check (docs/valute-in-tecaji.md). - No deposits [6a]: there is no deposit correction (6b goes with deposits);
correctStepDepositand every other deposit path leave the code. - A new circle: with fewer than
project_approvals(3) Heart members who may vote "for" (never the proposer or the recipient), no project can pass, so all inflow, the start included, accumulates in the reserve and moves to the first project that passes (said openly). - The start (decided 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, below under "Keyless accounts"); 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); 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 bystartandclose_waveand 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.
Target: rate quotes in the box (decided Q7, C5, E-1; start source decided 16 Oct afternoon)#
- Source: the node reads the source the circle chose (parameter
rate_sourcein thefoundact; proposal: changed by a Heart actrate_source_set, one Heart member's proposing act and endorsements, together from three of the four Heart members (the proposer counts)) and keeps its latest value with the source's publication time. Start source (decided):ecb-daily, the ECB euro foreign exchange reference rates (daily, public, free; EUR base with USD and GBP), read once a day after publication; on days without a new value the latest stays the source; the app always shows the source date; a quote is valid at mostquote_ttl_s(a parameter of the receiving circle, 600 s by default; decided 23 Oct 2026, E-1). Proposal: the node alerts the Heart members when its newest source rate is older thanRATE_STALE_ALERT_S= 432,000 s (120 h), a fixed constant of the definitions. Said openly: the ECB states its reference rates are for information only. the project owner's rate key may later be one source a circle chooses. - 43919 v3 Rate Quote (regular event, never replaced), the same format word for word as
docs/knjiga-na-relejih.md§3.7:pubkey= the node of the receiving (seller's) circle atcreated_at; tags["c", <circle id>],["source", <source id>, "<source unix time>"],["base", "EUR"],["rate", "USD", "<whole ppm>"],["rate", "GBP", "<whole ppm>"],["expires", "<unix ≤ created_at + quote_ttl_s>"](600 s by default; the receiving circle's parameter, by which both circles judge the quote: proposal),["prev", "<the circle's previous quote id or \"\">"],["v", "3"]. One live quote serves any payer untilexpires; the node issues a new one when asked and the old one has expired, has less than 120 s left (QUOTE_MARGIN_S, a fixed constant), or the source has a newer rate. - A payment across currencies: the payer's app fetches a valid quote from the receiving circle, shows
to_amount = floor(amount × r_to / r_from)(exact fraction in BigInt, never rounds up; today'sconvertMinor), and the payer signs one 43910 withamount,to_amount,["e", <quote id>, "", "quote"]and anexpiresno later than the quote's. The payer's circle runs the quote checks first and refuses an expired or wrong quote at intake, holding nothing. The receiving circle checks that the quote is its own, signed by its node at that height, that the payer circle'sxoutat≤ the quote'sexpires, and thatto_amountequals the conversion exactly. No panel, no median, no tolerance, no comparison with a "newest" record. Refusals:stale_quote(expired),bad_quote(anything else); the payer asks for a new quote. The payer's circle booksxdoneonly for axinwith the same note id and exactlyto_amount. - A hanging cross-circle payment [Decided 8j]: a timeout alone never undoes the payer circle's
xout; afterxcheck_s(7 days by default, the payer's circle's parameter) the payer's circle reads the receiving circle's ledger on its relays: not booked, with its seals covering the note'sexpires→xundoto the payer (reasonnot_booked); booked →xdone; unreadable or not yet sealed → wait and check again. Nobody pays a refund; there is noxrefund. The receiving circle never books anxinafter the note'sexpires. Proposal: the receiving circle's office is read from its own ledger (eachrolesentry in office from the next height), and each of its seals is judged with the office after itsh_to; a block of it counts only with a valid quorum of its witnesses in office at that height (a block without one, for example one signed only by old, retired or stolen keys that are no quorum of its witnesses in office at that height, is ignored; two blocks with valid quorums at one height are a fork, and the evidence is not used, so a key that was in office at a height, for example the single witness of a one-witness circle later stolen, can still stop the return by forking that height), so a key or witness change in the receiving circle does not stop the check. Full rule and encoding:docs/valute-in-tecaji.md, "The 8j check". - Both circles' blocks carry both amounts and the quote id; the payer's circle republishes the quote to its own relays, so it restores without the partner.
- Replaced: the hourly 43919 by the project owner's rate key (decision of 16 Oct morning, never built), the rate panel (
rate_panel,rate_rulemedian) and "the last rate stays valid" as a payment rule. Kept: no deduction, no threshold, history never overwritten.
Target: no payouts, no deposits, no bank data, names only by key (decided Q5, Q6, 6a)#
- No payout acts (
payout_request,payout_cancel,payout_sent,payout_reject), nopoutentry, noheld_outin the account line or the decision state, no bankreservestatement, no payout circuit breaker. Cover isamount ≤ balance + wave. A clone gets no payout routes and no payout pages (today it still has them:docs/implementation-notes.md). - No money deposits [Decided 6a]: no deposit acts (
deposit_declare,deposit_cancel,deposit_attest,deposit_reject,deposit_correct), nodeporcorrentry, no custodian (custodian_name, custodian lines in the decision state and the mirror), nomainaccount, nopaid_inin the account line, no deposit limits (question 12 goes), no deposit alarm. A clone gets no deposit routes and no deposit pages (today/api/step-depositsand the custodian flow inserver/custody.tsare live). A wave grows only from receipts. - No bank data in any event.
- Blocks, acts, seals, snapshot lines and the
joinentry carry only HEX keys, never a display name. Names live only in KIND 0 and the member home 30916 (itsnname words are rewritten when the name changes; relays keep only the newest replaceable version). No 43925 and no legal-review gate before the first public booking.
Target: keys (proposal P2; decided Q3, Q7, Q8, 8i, 6c, C5)#
- Today:
data/keys.json(mode 600) holds the circle, node and fund secret keys. - Node key = the box's signer key; it also signs the circle's rate quotes (decided Q7).
- Circle key: held by the app and the creator (decided 16 Oct); P2 (stays a proposal): the founder's browser plus a paper copy, so the first circle key is made in the creator's browser, and the
foundact names it (["circle_key", <hex>]; decided 17 Oct 2026, C5). Blocks are signed by the witnesses (decided Q3) and community money is keyless (decided Q8), so the circle key cannot book. Proposal (part of P2): it signs only the 30910 v3 mirror and, once, thefoundact's binding in block 1 (circle_sigoversha256("lb-found/3|" + found id)). It is only the stamp on the mirror and no longer names the circle (only the 30910's own address contains it, so readers query#d): the circle id names the circle, andscope16(the first 16 hex characters of the circle id), thectags, the keyless accounts and the 30915dall come from the circle id (decided 17 Oct 2026, C5). Proposal: the circle key is never the founder's key, a witness key or a Heart member's key (checked in every mirror and infoundandcircle_key_change). - The 30910 v3 mirror: tags in this order:
d(the circle id),code,name,currency,tz,tzdata,morning,g,mirror_of,founder,parent? (when the found act names one; decided 23 Oct 2026, E-8; the shape: proposal),circle_key(the key its mirror puts in office),signer…,quorum,proposer,steward…,stewards_required,relay…,archive…,bootstrap?,rate_source,api,definitions,v;quote_ttlandproject_approvalsare not in it (circle parameters, carried in the ledger's state; decided 23 Oct 2026, E-1). Arolesmirror never changescode,currency,tz,tzdata,morning, the circle id (d),founderorparent: they are written at founding (proposal; follows from C7 and the one currency per circle).g= [genesis digest, the founder's signature oversha256("lb-genesis/3|" + circle id + "|" + genesis digest)]. Its author must be thecircle_keyit names; its canonical address is30910:<circle key in office>:<circle id>, which changes when the key is replaced, so readers query#d= the circle id. A 30910 counts only if it is signed by the circle key that the ledger's mirror at itsmirror_ofnames (the genesis entry or a laterrolesentry; at the height of a key change already the new key, which is in office for blocks only from the next height), its tags withoutgequal that mirror and itsgis the pinned genesis; readers take the valid record with the highestmirror_ofand follow the ledger when they differ. Said openly: anyone can publish a 30910 that names a circle id; it counts only when the ledger's mirror at itsmirror_ofnames its author. - Replacing the circle key (decided 17 Oct 2026, C5; proposal: the act shape, the proof of possession and in office from the next block): a Heart member signs
circle_key_change(group Roles, text optional) with["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 can name a key someone else holds; the pop binds the act's time, so it 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; further Heart members endorse it by the endorsement form (["e", <first act id>, "", "proposal"], booked before the first act'sexpires). With k distinct current Heart members (three of four in the live circle) andchange_notice_s(72 h by default; decided 23 Oct 2026, E-1) of public notice from the k-th act, arolesentry booked by the witnesses puts the new key in office from the next block: governance lineg3|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; the new key is not the key already in office (proposal). A block books at most onerolesentry (proposal), somirror_ofnames exactly one mirror per height and a secondrolesentry can never undo the change; block 1 books norolesentry, since its genesis mirror is the mirror of height 1 (proposal). From then on only the new key signs the 30910, already the one whosemirror_ofis the change's own height (that mirror names the new key); a 30910 by the old key with amirror_ofat or above the change never counts. The circle id never changes. A stolen key and a lost key are replaced the same way, so neither ends the circle's mirror any more. Proposal: a day seal (43917) is judged with the office after its last blockh_to, the newest mirror at or below it: its witnesses sign the seal, and the seal names their set (signers) and that mirror's circle key (["circle_key", <hex>]), as the state'sg3lines ath_todo; at the height of a key change that is already the new key, which also signs the 30910 of that height. Every 30915 head copies it, so a reader of the root directory picks the right 30910 by that key. This answers the earlier open question: the notice is one circle parameter,change_notice_s, for every roles change (decided 23 Oct 2026, E-1). - Keyless accounts (decided: Q8 for
reserveand project wallets, 8i forworldandworld-step, 6c fororigin(the name: proposal); there is nomainaccount, it went with the deposits, 6a): they are x-only pointslift_x(sha256("lb-system/3|" + role + "|" + circle id + "|" + i))for the first decimalithat gives a valid point, with rolereserve,world,world-step,origin, or for a project walletproject|+ the 64-hex id of itsproject_proposeact (displayed asproject:<id>; the test vector is fixed in plan C1). Nobody can sign for them; onlyruleentries move them. The fund key goes; a 43910 authored by the old fund key is refused.
Target: independence of the cell (principle 5)#
- The signer set, the circle key in office, the relays and the rate source come from the circle's own log (cached ≤ 24 h), never from the newest 30910 or from root.
- Every partner block a circle relied on and every rate quote its blocks reference is republished to its own relays, so it restores without partners and without root.
- Apps read root (38888) only at first install; the link/QR (the circle id, relay hints and the genesis digest) is enough to find the circle (Q10). The circle parameters are in the circle's own ledger (
g3|param:*); there is no world rules record to read (43920 retired, decided 23 Oct 2026, E-1), so a restore needs only the circle's relays. A circle reads another circle's ledger only for the 8j check and to check a reference (E-9): a soft dependence on the network of circles, said openly (principle 5). - The definitions version is pinned in the
foundact and the governance lines; no act and no parameter changes it in 0.3.0 (how a circle moves to a later definitions version is not defined yet; proposal Q20). - The parameters in force are named by every block through its state (
g3|param:*andg3|params_h) and change only byparams_effectiveat the end of aparam_proposenotice, never retroactively (decided 23 Oct 2026, E-1; the entry: proposal). There is no rules authority any more: the one key with world-wide reach of 1A is gone, and with it that tension with principle 3 (E-1). - One circle must fit one relay: provisional cap 100,000 members at 10 payments a day (500,000 at 2 a day), raised only from measured numbers (Q13).
- Tests: a clone starts with its own relay; the policy refuses a KIND 5 against a block; the clone restores from its own relay alone to the same state; two test circles on separate boxes keep working when either box is stopped (reads continue; cross-circle payments follow the rule "a timeout alone never undoes", and after 7 days the 8j check returns a hold only when the stopped circle's sealed ledger shows the payment was not booked); a quote from another circle's node, or an expired quote, is refused.
Open in M4a#
DECAY_DEFAULTS.timeZone(Europe/Ljubljana) is the same in every circle. Target:tz, the morning hour and pinnedtzdatain thefoundact, fixed at founding for 0.3.0 (decided 17 Oct 2026, C7: no act or parameter changes them; a later definitions version may say how a circle follows new clock rules); a morning hour inside a clock change counts at the first occurrence of a repeated hour, or at the first instant after a skipped one; the morning header names that pinnedtzdata(the check: proposal), and a witness computes the boundary with that version, never with a newer one of its own (decided 17 Oct 2026, evening, 2A); a witness without that version signs no morning block and no seal (proposal).index.htmlmeta description ("balanced euros"); deposit and payout references started withD2A-(gone with deposits and payouts, plan step D0);users.communitydefaults toDance2Abundance; the healthservicename and log lines say Dance2Abundance. Cosmetic: nothing is booked wrongly.
Next (M4b and the plan's steps)#
- First start without settings: a setup page; in the founder's browser (P2) a new first circle key is made, the founder signs the
foundact that names it (its id becomes the circle id), and that circle key signs block 1's binding (circle_sig) and the first 30910 mirror; the server makes only the node key. Payouts and deposits removed from the code and the pages, with the custodian flow anddone 17 Oct 2026 (plan step D0; decided Q6 and 6a;system:maindocs/implementation-notes.md).- The box relay (plan F3), the restore drill against the relays (E5, F4), the Circle Heart (I1: the founder and three other Heart members by HEX; k = 3 of 4), the witness quorum (I2; witnesses by lot: phase I, E-7), projects and the reserve (E4c; open only 8g, 8h; the start of 6c is booked at genesis, E6), rate quotes and the 8j check (I3).
dandclientof the live circle stay; new circles use their ownd(today's 0.2.0 records; in 0.3.0 the 30910dis the circle id and the code is itscodetag, decided 17 Oct 2026, C5).