Files
hips/HIPs/hip-1202-entitlement.md
zeekayandHanzo Dev 7a9dcac628 What each runtime implements of the Hanzo corpus
An audit read the code and found the proposal that specifies it. Go reaches
all 122 capability proposals and 64 of the 121 other Standards Track ones;
Rust has 35, mostly the operator and the CLI; C++ has three, because the
complete original C++ in the estate is a ZAP handler, a bot nothing specifies,
and authored kernels inside forked CUDA and Metal crates.

    | | shipped | partial | none | not assessed |
    | Go   | 146 | 33 | 1 |  80 |
    | C++  |   1 |  2 | 0 | 257 |
    | Rust |  10 | 25 | 1 | 224 |

The large "not assessed" columns are the point rather than a gap. The model and
training specs are Python, the frontend and design-system proposals are
TypeScript, and recording `none` against those would read as a search that
came up empty when the honest statement is that the runtime was never the
question. Governance, Meta and Process are not graded at all.

Six proposals are Final with nothing found in Go and are left unwritten rather
than demoted: 0065, 0089, 0098, 0103, 0521 and 0902. HIP-0521 answers itself,
its own section reading "Not yet implemented". Three of the others name a
canonical Go file in consensus/protocol/auth that nobody wrote, in a package
where the four neighbouring proposals' files all exist with tests beside them.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-05 19:18:13 -07:00

5.6 KiB

hip, title, author, type, category, capability, status, implementation-go, created, requires
hip title author type category capability status implementation-go created requires
1202 Entitlement — What an Org May Run Hanzo AI Standards Track Platform entitlement Final shipped 2026-08-20 HIP-0106, HIP-0118, HIP-0139

HIP-1202: Entitlement — What an Org May Run

Abstract

entitlement answers what your org may run: which products the plan grants, and which of those the org has switched on. It is apps/entitlement in hanzoai/cloud, and its whole discipline is that those are two authorities, never braided — ENTITLEMENT is the billing truth, read from commerce at decision time; ENABLEMENT is the org's intent, the one store this capability owns (apps/entitlement/entitlements.go:1-33).

Motivation

A paywall whose grant check and toggle store are one table cannot say whether an org stopped paying or switched something off, and every consumer grows its own merge of the two. Keeping the billing truth in commerce and only the intent here means enabling never spends new money — a plan upgrade happens in commerce, not here — and disabling is never gated.

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 Addresses

operation what
GET /v1/entitlement the caller's plan projection: { tier, apps: {…} }, the per-app booleans the console shell renders (apps/entitlement/projection.go)
GET /v1/entitlement/orgs/{org} { "enabled": [...] } — the org's toggled-on products
POST /v1/entitlement/orgs/{org} { "add": [...], "remove": [...] } → { "enabled": [...] }, bounded at 64 products per batch (apps/entitlement/entitlements.go:59-61)

All three are typed operations. Today's router serves the org pair at /v1/orgs/{org}/entitlements, under a root this capability does not own; that pair is carried by hanzoai/cloud openapi/misfiled.txt and closes by fold, mirroring the /v1/kms/orgs/{org} shape the key service already serves.

§2 Store

One encrypted SQLite database, the deployment's own entitlement, opened through the one opener (sqlpool.Open("entitlements", dir), apps/entitlement/store.go:47) and keyed (org, product). Product ids and org labels are validated at the edge against the one product-id and org-label shapes (apps/entitlement/entitlements.go:63-72).

§3 Tenancy

{org} MUST equal the caller's validated org (c.Org()), unless the caller is a SuperAdmin — c.IsAdmin(), minted only for owner == "admin" and never client-forgeable — who may target any org (HIP-0118). A bearer-less request with a restored X-Org-Id and no verified user fails the principal.Validated gate and is refused 403 (apps/entitlement/entitlements.go:26-32). There is no path by which one org reads or writes another's entitlements.

§4 The gate, and its two fail directions

A product may only be ENABLED if it is ENTITLED: the write reads commerce.CheckEntitlement and a non-SuperAdmin can only switch on what the org already pays for; a SuperAdmin bypasses the gate — the operator can comp any product to any org. With commerce unreachable, a non-SuperAdmin enable fails closed, 503, never open (apps/entitlement/entitlements.go:74-77). DISABLING is always allowed.

The two read paths fail in deliberately opposite directions (apps/entitlement/projection.go:9-17): the UI projection fails safe-to-locked — commerce down means an app reports false at 200, never a 5xx — while the enforcement leg (RequireProduct, apps/entitlement/require.go) fails open, so functionality is preserved during a billing outage even as the UI conservatively shows locked. The plan → product policy itself lives once, in the catalog commerce resolves; it is never restated here.

§5 Metering, events, observability, stage

The capability is free (plugin/entitlement/main.go:22, cloud.Free). It publishes no events on the bus and delivers nothing to customer webhooks. Beyond the request span, it emits its mount line and one audit-shaped log per mutation — org, add, remove, whether SuperAdmin, and the actor (apps/entitlement/entitlements.go:306). Its stage is ga — the manifest row (manifest/apps.go:366) carries no stage.

§6 Upstream

The capability derives from no forked, embedded or mirrored OSS project. Its one non-standard-library import beyond the app framework is github.com/hanzoai/account v0.3.3 (MIT OR Apache-2.0), the billing-account rule as a library.

Rationale

The alternative to the opposite fail directions is one posture for both reads. Failing everything closed turns a commerce outage into a product outage; failing everything open renders upgrade UI as if every org owned every plan. Splitting by consequence — enforcement preserves function, projection preserves honesty — costs one paragraph of doctrine and buys an outage that degrades instead of cascading.

Security Considerations

The wrong implementation grants product for free or across tenants. Skipping the entitlement leg on enable turns the toggle store into a self-serve comp system; the commerce read at write time is the control, and its fail-closed posture for non-SuperAdmins is what keeps an outage from becoming a giveaway. Trusting a per-org isAdmin instead of the one SuperAdmin predicate is the privilege escalation HIP-0118 names. The org label folded into the store key is validated strictly at the edge, so a crafted {org} cannot address another tenant's rows.

References

  • HIP-0106 — The Hanzo Plugin Contract
  • HIP-0118 — SuperAdmin & Tenant Isolation Model
  • HIP-0139 — Capability

Released under CC0 1.0 Universal Public Domain Dedication.