Skip to main content

EntitlementFact

Struct EntitlementFact 

Source
pub struct EntitlementFact {
    pub tenant: TenantId,
    pub plan: String,
    pub state: State,
    pub paid_until_unix_ms: Option<u64>,
    pub caps: BTreeMap<String, u64>,
    pub source: String,
    pub signature: Vec<u8>,
    pub issued_unix_ms: Option<u64>,
    pub issued_signature: Vec<u8>,
}
Expand description

The verdict monetize pushes back. Product-agnostic; the plugin maps it to the product’s own enum (gunnar: EntitlementState).

Fields§

§tenant: TenantId§plan: String

The ORDER this verdict came from — the ledger reference (<product>/<tenant>/<date>+<caps>) for a purchase, an operator’s own label (or nothing) for a hand-set fact. The field is still called plan on the wire and in the signed canonical form (monetize_embed::signing), because gunnar verifies that form and a renamed field would invalidate every signature a deployed gunnar checks; the CONTENT is an order reference since the plan catalogue went on 2026-09-05.

§state: State§paid_until_unix_ms: Option<u64>§caps: BTreeMap<String, u64>

Per-meter caps the product enforces itself (gunnar: pack_quota_bytes, explode_budget_bytes). Absent = product default.

§source: String

operator | payment:<vendor>:<reference> — lands in the product’s attestation log.

§signature: Vec<u8>

Ed25519 over the canonical JSON of the fields above, by monetize-server’s key. The V1 form — it does NOT cover EntitlementFact::issued_unix_ms, and that is deliberate: it is the signature an appliance built before 2026-09-17 computes, and it must keep verifying there for ever. See Self::issued_signature.

§issued_unix_ms: Option<u64>

When monetize issued this verdict — the field that makes a fact good ONCE.

Without it an EntitlementFact is replayable for ever: capture a Paid fact, wait for the tenant to lapse, push the captured bytes back, and the signature still verifies because it is a real signature. paid_until cannot tell the two apart — a lapse keeps the date and moves the ladder — so the only thing that can is something MONOTONIC inside the signed form. A product refuses a fact that is not newer than the one it holds (gunnar: EntitlementSlot::set).

Unix milliseconds, and not a sequence number, for the same reason crate’s sibling [monetize_embed::signing::Snapshot] chose one: a clock needs no durable per-tenant counter on monetize’s side, so a restored ledger cannot rewind one and mint facts every appliance in the field then refuses for ever. One idea in this system, not two.

None is a fact signed before this field existed. It stays legal, and a product accepts it — until that product has seen ONE stamped fact for the tenant, after which the unstamped form is a downgrade and is refused.

§issued_signature: Vec<u8>

The V2 signature: Ed25519 over the canonical JSON of every field above INCLUDING issued_unix_ms (monetize_embed::signing::fact_message_issued).

Two signatures and not one, because a fact has to be readable by two generations of appliance at once. An appliance that predates this field reads only fields 1-7 off the wire, computes the V1 form, and checks Self::signature — so it accepts a stamped fact unchanged, and a paying customer on an un-upgraded box loses nothing. An appliance that knows the field checks BOTH, so the issue time is signed and cannot be added, moved or bumped by whoever relays the fact.

Empty exactly when issued_unix_ms is None; neither is legal without the other.

Trait Implementations§

Source§

impl Clone for EntitlementFact

Source§

fn clone(&self) -> EntitlementFact

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EntitlementFact

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for EntitlementFact

Source§

fn deserialize<__D>( __deserializer: __D, ) -> Result<EntitlementFact, <__D as Deserializer<'de>>::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for EntitlementFact

Source§

impl PartialEq for EntitlementFact

Source§

fn eq(&self, other: &EntitlementFact) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for EntitlementFact

Source§

fn serialize<__S>( &self, __serializer: __S, ) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for EntitlementFact

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.