HIP-1000: Author — A Royalty Bound to a Repository
Abstract
/v1/author is a royalty program: an author proves control of a repository, and
every org that deploys a project built from that repository generates a royalty
against its own metered spend. It is implemented in hanzoai/cloud at
apps/author. This HIP states the contract the program must hold to — how
attribution is proven, how a royalty amount comes to be, and the line between
recording money and moving it.
Motivation
Open-source work already runs on the platform and already generates spend. There
was no edge connecting the two, so the spend had no author and the author had no
claim. apps/author supplies that edge; this HIP supplies the rules it must not
break, because every one of them is about somebody else's money.
Specification
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.
Attribution proves control of code, not identity of a person
A repository earns only after a verification that demonstrates control over it:
either a forge token showing admin or push permission, or a file on the default
branch carrying the author's minted verify code (apps/author/authors.go:20-23).
Both prove the same fact — that the claimant can change what that repository
deploys. Neither is a claim about who the claimant is, and the program MUST NOT
treat it as one.
A deploy edge is recorded per (repo, project, deploying org) and is idempotent
(apps/author/authors.go:24-26). Without that edge nothing accrues, so an
unattributable deploy earns nothing rather than earning by default.
The royalty is a latch, not a computation over history
Accrual is at most once per (author, deploying org, period). The amount is that
org's metered spend for the period times the share stored on the author at that
moment: earningCents = spendCents * shareBps / 10000
(apps/author/basis.go:48), evaluated in accrueOne
(apps/author/authors.go:336).
The row written by the latch captures share_bps, spend_cents and
earning_cents in the same transaction as the balance increment. That row is a
value, and it MUST be served verbatim and never recomputed
(apps/author/basis.go:15-30). A later rate change, a share renegotiation or a
restated spend figure therefore cannot rewrite what an author was already told
they earned.
The current rate card is a model, not a value, and MUST be served separately
and labelled with its asOf. Stamping a card onto a historical row would be a
fabrication by construction: one row's spend can span several cards' pricing
windows, and some of its components were never priced by a card at all.
An author's own org is excluded from the fold (apps/author/authors.go:311-313),
so the program cannot pay a royalty on self-dealing.
A per-org spend read that fails is skipped and picked up on the next sweep
(apps/author/authors.go:320-323). A partial answer that is correct beats a
whole answer that is wrong.
Accrual records what is owed; payout records a disbursement; neither moves money
accrued only rises. paid rises only when a payout is recorded, and a payout
MUST NOT exceed pending = accrued − paid, reserved atomically before anything
else happens (apps/author/store.go:1058-1064, refusal text at
apps/author/typed.go:113-117). A recorded payout that the treasury cannot back
is voided rather than left standing (apps/author/store.go:1100).
No route in this capability settles money. A human does that out of band. The program is a ledger of obligation.
Identity is never an input
The earning org is read from the validated principal, never from a request field.
The platform-wide operations are admitted only by a SuperAdmin bit that the
identity boundary mints and that the ordinary principal does not carry
(apps/author/typed.go:84).
The support view of an author's basis MUST be produced by the same builder as the
author's own read (apps/author/typed.go:845), so support and author can
never be looking at two numbers.
Store, price, events, telemetry, stage, upstream
The capability owns one encrypted SQLite database, author, opened through the
one opener (sqlpool.Open("authors", dir), apps/author/store.go:177). It is
free, in those words: Price: cloud.Free (plugin/author/main.go:21) — it
records obligations and meters nothing. It publishes no events on the bus, so a
customer's webhooks receive nothing from it; money actions land best-effort
records on cloud's audit trail (apps/author/authors.go:133, :475-479).
Beyond that and the request span it emits log lines only. Its stage is beta —
the manifest row declares it (manifest/apps.go:388, Stage: Beta; HIP-0139
§8). It derives from no forked, embedded or mirrored OSS project.
What this refuses
- No disbursement. There is no address here that moves money, and adding one would put a mint authority behind an accrual sweep.
- No recomputation. There is no address that re-derives a historical row.
- No per-row rate card. The card is current or it is absent.
- No 404 on "not enrolled". A caller who has never enrolled gets an honest
short answer, because 404 on that address answers "is this org an author" to
anyone who asks (
apps/author/typed.go:208-210).
Rationale
The obvious alternative is to compute the royalty on read: keep no ledger, and derive the number from current spend and the current share whenever someone looks. It costs auditability. The author's dashboard number would change when a rate changed, without anything having happened, and no one could reconstruct what they had been told last month. The latch buys immutability for the price of one row.
The second alternative is to settle automatically at sweep time. That braids a disbursement authority into a scheduled job, which is the shape where a single arithmetic defect becomes a fleet-wide payout. Splitting accrue from pay means the worst outcome of a defect in the sweep is a wrong number on a screen.
Security Considerations
Verification is the only thing standing between an arbitrary caller and another project's earnings. The file method proves default-branch control, which is the right property — someone who can change the default branch can already change what deploys — but it does mean a repository whose default branch is writable by many is claimable by any of them.
The share and status operations sit behind the SuperAdmin bit. That bit is a header only the identity boundary can mint; any deployment that lets a client set it directly hands over the ability to approve authors and record payouts.
The payout ceiling is the one arithmetic guard that stands between a recorded obligation and an over-payment, and it is enforced by reservation rather than by a read-then-write, because a read-then-write races.
References
- HIP-0135 — What Is Public
Copyright
Released under CC0 1.0 Universal Public Domain Dedication.