monetize-embed 0.1.2

The thin client a monetized product compiles in: an Ed25519-verified entitlement cache with nanosecond verdicts that keeps answering while the licence server is unreachable. No network, no ledger — the product feeds it signed facts and asks.
Documentation

monetize-embed — what a product compiles in. One struct, one question: does this tenant get to do this, right now? Answered from verified facts held in memory, in nanoseconds, with monetize down or not.

  monetize-server ──signed Snapshot file──▶ EntitlementCache::refresh   (start, catch-up)
  monetize-server ──signed EntitlementFact─▶ EntitlementCache::push      (every change)
  product choke point ──────────────────▶ EntitlementCache::allows     (every request)

The ladder table, as the product sees it

state Write (push, LFS upload) Read (owner clone/fetch) AnonymousRead Admin (UI)
Free, Paid allow allow allow (product still applies Public) allow
Grace allow, [EntitlementCache::notice] has the warning line allow allow allow
Suspended refuse, named reason + URL allow refuse refuse: pay page only
Retention refuse allow (export) refuse refuse: pay page + export

Two rules, not negotiable: never hold data hostageRead is allowed in every state, a lapsed tenant can always clone their own repositories; and refuse before the bytes — the product asks at authorise_service, before a pack is read, and puts [Verdict::Refuse::reason_line] in report-status.

What is, and is not, decided here

  • The state in a fact is monetize's verdict at push time. The cache does not re-derive it as the clock moves — it does not know the policy's day counts, and the product contract says a product keeps serving on its cached entitlement when monetize is unreachable. Ladder transitions arrive as new pushes.
  • An unknown tenant is Free: the product's default, never a refusal.
  • Visibility (Public) and quotas (caps) are the product's own checks; this crate only says whether the entitlement allows the kind of action.

Cost of the read path

[EntitlementCache::allows] is one ArcSwap::load (an atomic increment on a debt-slot, ~2 ns, no lock, no allocation), one BTreeMap lookup on the tenant name, and a match. A refusal allocates its two strings; an allow allocates nothing. Writes (push, refresh) clone the map and swap the pointer — O(tenants), taken by the rare path on purpose so the hot path never contends.