Verification
Verification is one pure function. The chain, the KYB attestation, the
consent grant, the revocation set, the current time, and the verifier’s list of
trusted attesters all arrive as arguments — the function does no I/O and reads no
clock. The identical logic runs in the verifier portal, the worker wallet, and
the dependency-free offline page, and is mirrored byte-for-byte in TypeScript.
The implementation is
crates/tenure-core/src/verify.rs.
Because the current time and the freshness window are inputs rather than globals, the same bundle yields a deterministic verdict for any chosen clock and recency policy — and the verifier owns its trusted-attester list the way a browser owns its root store.
The five checks
The predicate runs in order and returns the first failure, or Verified. (A
prerequisite step first confirms the employer descriptor is signed by the
employer key it declares.)
- KYB. A valid, unexpired KYB attestation binds the employer key to the displayed legal entity, and the attester that signed it is in the verifier’s trust list. A failure here always names which attester signed — even an untrusted one — so the verifier can decide for itself.
- Chain. The epoch chain verifies back to the employer key; each
attestation is signed by the registrar of its epoch, sits inside that epoch’s
sequence range, and is covered by a delegation that allows its type and
contains its
as_of. A mint outside every delegation is rejected here even though it is signed. - Consent. The share grant is signed by the worker’s per-employer key, is unexpired, names every presented attestation, and matches the audience presenting it.
- Freshness. If any presented attestation is in the revocation set, the
verdict is
Revokedregardless of head age. Otherwise, if the checkpoint is older than the freshness window, the verdict isStaleHead— evidence decays by design, so a saved bundle past the window can never readVerified. - Resolution. A claim verifies only if its family is the
latest unsuperseded family for its fact; a stale variant — exact, band, or
threshold — is rejected, as is any attestation whose own
valid_untilhas passed.
Verdicts
The verdict is explicit and never scored. Verified proves the employer
signed the statements — not that they are true.
| Verdict | Meaning |
|---|---|
Verified | All checks pass. Carries the employer’s legal name, the attester and its methods, the claims at the granted granularity, and the “not revoked as of” time and head age |
Revoked | A presented attestation or its family is revoked or superseded |
GrantExpired | The share grant has expired |
ChainInvalid | A structural failure — broken chain, mint outside delegation, tampered bytes — with a reason |
EmployerUnverified | KYB failed or the attester is not trusted; names the attester that signed |
StaleHead | The checkpoint is older than the freshness window |
The verdict card distinguishes an offline check (against a head from, say, 13:40) from a live recency check, and shows the head age explicitly.
Importing a full log
Verifying a presented bundle is the common path. Importing an entire log — a ragequit file, or a new registrar adopting an employer — is stricter and runs once: it verifies the descriptor, the KYB attestation, the epoch chain, and every delegation, then replays every entry (registrar signatures, hash-chain continuity, and type/rate-cap accounting), verifies the final signed head, and materializes the current state plus the revocation set. A new registrar runs exactly this before reporting its head, which the Signer then cross-checks against the heads it witnessed. See Misbehavior & switching.