Repository navigation
feat(spec): kit royalties, slice 1: licenseHash, the lineage split, and an exact computeKitSplit (R4) - #492
Merged
Merged
Conversation
…nd an exact computeKitSplit (R4) R4 / board item 13: contributors are paid when their code executes. A Kit version carries a #360 License whose one payment requirement is a percent of the gross of every unit that runs the kit, paid to the kit's fork lineage, as ordinary payout legs in the unit's release (DESIGN.md in the lane's return; kits #4102 and adk #4056 agreed the shape). This slice is the pure economics side: - licenseHash(license): H("PCC:license:v1", License), "0x" + 64 lowercase hex. The License is read once as plain JSON and schema-checked first, so equal Licenses hash equal and a malformed one is refused. Kits pin it as economics.economicTermsHash. - kitLineageDistribution(lineage): - Nearest first: the publisher alone, 2 : 1 for a direct fork, 4 : 2 : 1 for the nearest three. Nothing past the grandparent is paid. - A self-fork merges into one member with the summed weight, in lowest terms. - Members are sorted by party id, the order the compiler compares a requirement in. - kitRoyaltyRequirement({bps, lineage}): a percent of gross, per using unit, to that distribution. A free kit (0 bps) requires nothing. - computeKitSplit({quoteMinor, currency, feeBps, licenseBps, lineage}): what a buyer funds for an operator's quote with the royalty on top. The result is the smallest gross the accepted-plan seam accepts, its fee, the royalty, the operator's part and each contributor's share. It runs the compiler on a one-unit agreement (kitSplitAgreement, exported), so the numbers are exactly what settlement pays. For a $25.00 quote at PCC's 2.35% fee with a 0.50% royalty: gross 25.128666, fee 0.590523, royalty 0.125643, operator 24.4125 (the quote less the fee on it). Tests: 9 new. They include a 200-case sweep in which the real seam (netSplitterFor) accepts each computed gross and refuses one base unit less, and every unit conserves. Spec 1295/1295; tsc clean. Not in this slice: folding a share under the smallest leg into the forker's, and the per-unit cap over all kits. Both need a compiler rule after the operator rules on the rates (item 99). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ts, refuse a free kit and non-canonical quotes Cross-family review EC4 (astra, SHIP-WITH-FIXES at 320687f; three MEDIUM, two LOW). Each finding was reproduced at 320687f first: - M1: computeKitSplit read the caller's lineage more than once. Astra's getter, which answers ann for six reads and bob after, made it report bob receiving the royalty compiled for ann (`expected [ 'bob' ] to be 'refused'`), and `new Array(1)` threw "Reduce of empty array". Now every field is read once, as an own data property: the quote, currency, fee, rate and lineage. The lineage must be a dense array of party ids, copied and frozen. The distribution is computed once and used for both the agreement and the shares. Accessors, holes and non-ids are refused, never thrown. kitLineageDistribution and kitRoyaltyRequirement read their input once too. - M2: KIT_LINEAGE_WEIGHTS was a mutable array, so assigning [0] = 8 gave 8 : 2 : 1. It is now frozen, and the assignment throws. - M3: kitSplitAgreement crashed on a free kit (TypeError on a null requirement). It now refuses any input computeKitSplit would refuse with a RangeError, a free kit included. - L1: quotes "0x10", "+16" and " 16 " were accepted as 16. A string quote must now match the economics amount grammar (digits only, no sign, no leading zero), or the quote is a non-negative bigint. - L2: the sweep's Number LCG passed 2^53 and degenerated. Run in the test's own arithmetic, it never generated lineages 3 and 5 (counts {0:65, 1:1, 2:65, 4:69}). The sweep now runs every lineage x fee x rate explicitly, with BigInt quotes (270 cases), and asserts that every lineage ran. Documentation only, from astra's notes: - licenseHash is a content hash of the License as written, so reordering an array changes it. - computeKitSplit assumes the operator is not one of the lineage's payees. Tests: spec 1300/1300 (14 in economics-kits); tsc clean. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Oct 3, 2026
… defaults money Verdict 115b on #464. 16 new guards in starter/bin failed at 932c0ae. Now 41 tests pass: - F2: "completed" is sent only after an evidence receipt that says "stored": true for this jobId. The relay answers 200 with stored:false for an unknown job or a storage failure. New index event: verify.evidence-not-stored. - F3: nothing calls the result verified. It is a registered kernel exercised by one real job, whose evidence stays unverified until the operating agent signs it (README, AGENTS, CLAUDE, phases 5, 6, 9, graph). - F4: the capability is priced from .pcc/intake.json, not a literal 25. register-device lists no capabilities, so no zero-priced duplicate. The payout wallet is asked in phase 0 and sent at provisioning, where it becomes the operator id. The buyer test stops (verify.price-mismatch) unless the quote equals the human's price. The license rate is never offered or written as a default. The publish text follows economics (#4807, #492). - F5: the e-stop drill says what it shows (the gateway refuses new jobs for a stopped kernel; the device's own stop works) and what it doesn't. pcc-node 0.1.1 does not read the flag. - F6: the envelope digest is re-checked against envelope.confirmed.json before any run (phases 6 and 7). - F7: the kernel is fetched and checked before its signing key is registered. - F8, F9: runbook.json matches the phases. Register no longer needs pcc-node start, verify asks for the drill, and target.default is null. - F10, F11: pcc-report never raises on a malformed gateway address or unwritable state, and repairs a permissive .pcc to 0700. Phase 0 chmods .pcc too. - The kernel's text address goes in physicalAddress. Also for 0.1.1: pcc-node needs https or http to 127.0.0.1/[::1]. Don't run pcc-node start beside the loop, because its heartbeat says acceptingJobs: false. The install pin moves to release r2 @dcc44db9. F1 (operator-route ownership) is the gateway's WP-C; until it carries it, onboard only on a private gateway. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
changed the base branch from
feat/economics-agreement-compiler
to
master
October 4, 2026 00:45
LamaSu
marked this pull request as ready for review
October 4, 2026 01:18
LamaSu
added a commit
that referenced
this pull request
Oct 4, 2026
…arrel conflict resolved) #492 merged as a4e7847. Both PRs append exports to packages/spec/src/economics/index.ts after "./examples.js": #492 adds kits.js, and #394 adds preview.js, rates.js and { snapshotJson } from input.js. The resolution is the union of the two reviewed lists, in that order, with no other line changed. It is the same resolution simulated and posted to the steward (#6350). Every other file merged without a conflict. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
R4 contributor pay, slice 1 (board item 13): kit royalties, priced exactly
Contributors are paid when their code executes. A Kit version carries a #360 License whose one payment requirement is a percent of the gross of every unit that runs the kit, paid to the kit's fork lineage. It is paid as ordinary payout legs in that unit's release: no second ledger, no claim step. The design, fee levels and lineage rule are in the economics lane's return (
r4-contributor-pay/DESIGN.md). Kits (#4102) and adk (#4056) agreed the shape.Stacked on #360 (R15-core, astra SHIP; merge-ready at 8fe16b6). Retarget to master after #360 merges.
What this adds (pure functions in
@pcc/spececonomics)licenseHash(license):H("PCC:license:v1", License), "0x" + 64 lowercase hex. The License is schema-checked first, so a malformed one is refused, never hashed. Kits pin it aseconomics.economicTermsHash.kitLineageDistribution(lineage):kitRoyaltyRequirement({bps, lineage}): the License's payment requirement. It is a percent of gross, per using unit, paid to that distribution. A free kit requires nothing.computeKitSplit({quoteMinor, currency, feeBps, licenseBps, lineage}): what a buyer funds for an operator's quote with the royalty on top.kitSplitAgreement), so the numbers are exactly what settlement pays.Example: a $25.00 quote at PCC's 2.35% fee with a 0.50% royalty to a fork of a fork.
Tests
netSplitterFor) accepts each computed gross and refuses one base unit less;Not in this slice
🤖 Generated with Claude Code