Objects
Every protocol object is signed and transmitted in the same shape: the exact
canonical bytes plus an Ed25519 signature over them. The only bytes ever signed
or hashed are bcs(("tn-xxx-v1", body)) — a BCS body tagged with its object
kind. Because the tag is inside the signed bytes, a signature over one object
kind can never be replayed as another, and JSON renderings exist only for
display.
Verification always runs over the bytes as transmitted and only then decodes
them under the expected tag, so a single tampered byte fails the signature check
before the payload is ever interpreted. The authoritative definitions are in
crates/tenure-core,
with a TypeScript twin.
Object catalogue
| Object | Tag | Signer | Purpose |
|---|---|---|---|
EmployerDescriptor | tn-employer-v1 | Employer | Declares the employer key, KYB reference, enabled attestation types, dispute & recovery policy, mirror URLs |
KybAttestation | tn-kyb-v1 | KYB attester | Binds employer_pk to a legal entity + jurisdiction, with verification methods and an expiry |
EpochOpen | tn-epoch-v1 | Employer | Opens an authority epoch: names the registrar key valid from a given seq, chains to the prior epoch head |
EpochClose | tn-epoch-close-v1 | Employer | Closes an epoch at a final seq + head hash |
Delegation | tn-delegate-v1 | Employer | Grants the registrar the right to mint specified types up to a daily cap, within a seq and time window |
BatchManifest | tn-batch-v1 | Employer | Carries Signer-computed aggregates + the raw batch hash for one issuance run |
Attestation | tn-attest-v1 | Registrar | One signed claim about a worker, under a covering delegation |
StatusChange | tn-status-v1 | Registrar | Closes or reopens an employment period |
Revocation | tn-revoke-v1 | Registrar / Employer | Revokes one attestation, with a reason |
FamilySupersede | tn-family-supersede-v1 | Registrar | One log entry that atomically retires every variant of a claim family |
Reissue | tn-reissue-v1 | Registrar | Re-points attestations to a fresh subject key during recovery |
ShareGrant | tn-share-v1 | Holder | The worker’s consent record: which attestations, audience, scope, expiry |
GrantRevoke | tn-grant-revoke-v1 | Holder | Withdraws a ShareGrant |
LogHead | tn-loghead-v1 | Registrar | A signed witnessed head: employer, epoch, seq, head hash |
Checkpoint | tn-checkpoint-v1 | Registrar | A timestamped head mirrored externally; its published_at is the “not revoked as of” line |
Two consequences are worth calling out. Consent is the worker’s own signature:
ShareGrant and GrantRevoke are signed by the holder, not the registrar — not
a server toggle. And the batch manifest’s aggregates are computed by the
Signer, not the dashboard, so the registrar can cross-check them against the
raw batch it received.
Claim schemas
An Attestation carries a typed claims body and, for income, a basis. There
are seven claim types:
| Type | Claims |
|---|---|
employment_status | status (active / ended), start date, optional end date |
tenure_dates | start date, optional end date |
role_title | title, optional department |
income_exact | exact cents, basis |
income_band | floor cents, ceiling cents, basis |
income_threshold | “at least” cents, basis |
hours_class | class (full-time / part-time / variable) |
The basis qualifies income figures as an annual_salary, the
trailing_90d_annualized, or the trailing_12m. Income is never minted as a
lone exact value: the exact figure and its derived band and threshold variants
are minted together as one claim family.
What locates and bounds an attestation
Beyond its claims, an attestation carries the identifiers a verifier needs:
an attestation_id, the family_id shared by every variant of one fact, the
employer_id/epoch_no/log_seq that place it in the log, and the worker’s
per-employer subject_pk. as_of is the moment the claim describes;
valid_until is its optional expiry; supersedes_family points at the prior
family it replaces.
A registrar’s signature on an attestation only counts if a covering delegation
allows its type at that log_seq and its as_of falls inside the
delegation’s time window — see Verification.