The Resolver
Payment goes straight to each creator's published pointers — no OMLA account, no OMLA server, no report filed anywhere. The resolver is the deterministic function that gets you from "here's what I owe" to "here's who gets what." It runs entirely on your machine.
What it does
Take a model's signed manifest, the manifests of everything in its lineage, and a revenue figure for one calendar quarter. Out comes an exact split, in integer cents, per wallet:
{ "alice_wallet": 285000, "bob_wallet": 15000 }
That's $2,850.00 to Alice and $150.00 to Bob — cents, not floats, because money math should never round the way floating point does. Alice built the base model; Bob fine-tuned it. Bob's fine-tune retains at most 5% of what it's owed (License §6); the other 95% flows upstream to Alice, recursively through however many generations of lineage separate them.
A worked example
Say a company used Bob's fine-tune in a product that generated $10,000 in attributable revenue this quarter. Bob's manifest declares fine-tune lineage against Alice's base model. The royalty owed under the License is 30% of $10,000 = $3,000.
| Step | Result |
|---|---|
| Royalty owed (30% of $10,000) | $3,000.00 |
| Bob's retained share (declared split — the suggested 5%) | $150.00 → Bob's wallet |
| Upstream to Alice (the remaining 95%) | $2,850.00 → Alice's wallet |
If Bob's model had its own downstream fine-tune paying royalties through it, the resolver would flatten that whole chain in one pass — every wallet in the lineage gets its exact share, computed the same way regardless of how deep the chain runs.
When one output uses more than one model
The example above is a lineage — one model built on top of another, resolved by walking a family tree. A lot of real products don't work that way. An image generator might run a base checkpoint together with two independent LoRA adapters selected per-request; none of the three is "built from" either of the others, they're just used together for one output. Lineage math doesn't apply — the base model and each LoRA are separately published, separately licensed, and none of them owns the other's royalty. Call this a stack, to keep it distinct from lineage.
Splitting a stack needs a second, much simpler idea on top of the resolver: a declared generation weight per model, and a per-Model generation count. Neither requires per-dollar accounting — an inference server already knows which models were active for a given request, and that's the only new bookkeeping this needs.
The default weight schedule
Every Manifest may declare a generation_weight_bp — its stack weight in integer basis points of the reference unit (default 10000, i.e. full weight, if omitted; a LoRA typically declares 1000, i.e. 0.1×). The ratios below use the × form for readability. It's a rough, deliberately simple stand-in for how much of a generation a model is responsible for — not a precise compute measurement, and not meant to be one:
| Model type | Default weight | Why |
|---|---|---|
| Foundation / base model | 1.0 | The reference unit. Runs the full forward pass. |
| Full fine-tune | 1.0 | Replaces the base for that generation rather than adding to it — it doesn't stack, it substitutes. Its own credit to the model it was tuned from flows through lineage retention caps, not this table. |
| Quantization | inherits source | An efficiency transform, not new authorship — attribution passes through unchanged. (Separately, the quantizer's own cut of its own royalty share is still capped at 2% under lineage — a different axis from this table.) |
| LoRA / low-rank adapter | 0.1 | Typically well under 1% of the base's parameters and a small fraction of the extra inference compute. 0.1 is a deliberately generous round default, not a FLOP measurement — a creator can declare a different value in their own Manifest (a high-rank adapter, for instance), and a payer uses that declared figure when building the usage vector it feeds the resolver. |
This is a published convention, not a mandate — Section 2.4 of the License lets a Licensee use any reasonable method to compute revenue attributable to combined models. Direct measurement (if a product genuinely can trace revenue per model) always works too. This exists for the common case where it can't: a flat subscription, a free tier subsidized by a paid one, a generation that silently used three models at once.
A worked example: fine-tune + two LoRAs
An image-generation app charges a flat $10,000/quarter in subscription revenue — no per-image billing, so there's no natural way to trace a dollar to a specific model. During the quarter it logged 100,000 generations: 60,000 used the base checkpoint alone, 30,000 added a LoRA ("anime style"), and 10,000 added a different LoRA ("product photography"). The base checkpoint is itself a fine-tune of a foundation model, so its own share still owes 95% upstream under the existing 5% fine-tune retention cap.
| Step | Result |
|---|---|
| Royalty owed (30% of $10,000) | $3,000.00 |
| Apportioned by generation share — base-only stack (60,000 / 100,000) | $1,800.00 |
| Apportioned by generation share — base + LoRA-A stack (30,000 / 100,000) | $900.00 |
| Apportioned by generation share — base + LoRA-B stack (10,000 / 100,000) | $300.00 |
| Within base+LoRA-A, split 1.0 : 0.1 | $818.18 to base · $81.82 to LoRA-A |
| Within base+LoRA-B, split 1.0 : 0.1 | $272.73 to base · $27.27 to LoRA-B |
| Base checkpoint's total share (1,800 + 818.18 + 272.73) | $2,890.91 |
| Base checkpoint's own lineage: fine-tuner keeps 5%, foundation model gets 95% | $144.55 to fine-tuner · $2,746.36 to foundation model |
Final split of the $3,000.00: $2,746.36 to the foundation model's creator, $144.55 to whoever fine-tuned it into the base checkpoint, $81.82 to the LoRA-A creator, $27.27 to the LoRA-B creator. It adds up exactly — integer cents, largest-remainder rounding, same as everything else the resolver computes. Nobody involved needed to know the others' revenue, wallet, or identity to get paid correctly.
The API
OMLAResolver.flatten(manifests) -> { model_id: [{ wallet, units, via_models }] }
OMLAResolver.resolve(opts) -> settlement sheet or percentage estimate
OMLAResolver.manifestHash(manifest) -> Promise<sha256 hex>
OMLAResolver.CONSTANTS -> { UNITS, DUST_UNITS, DEPTH_CAP, ... }
resolve() takes a usage vector (which models were used, and in what proportion), the flattened wallet vectors for those models, and — when you have a dollar figure to distribute — a total in integer cents plus the calendar quarter it belongs to (YYYY-Q1 through YYYY-Q4). Without a dollar figure it still returns the exact percentage each wallet is owed, which is enough to sanity-check a manifest before any money is involved.
Why you can trust the output
- Deterministic. Exact integer/rational arithmetic throughout — no floating point ever touches a share. The same manifests and the same usage numbers produce the same result, byte for byte, every time.
- Runs locally. No network call, no OMLA API, no server in the loop. The whole implementation is about 600 lines — roughly half of them comments and validation — and you can read every one, or hand them to your own counsel or engineers to read.
- Open source. The implementation here is a verbatim copy of the reference implementation maintained alongside the license and the registry — read it, fork it, reimplement it in another language against the published spec.
A published npm package (@omla/resolver) with a version pinned by SHA-256 in the operative License is planned for the finalized v2.1 release — see the Copyleft or Pay section and the project plan.