Architecture
Tenure is confederal: each employer is a sovereign island of authority, and the only infrastructure that touches an employer’s data is the one that employer hired. There is no global chain, no server-to-server gossip, and no consensus protocol. This page describes the actors and the trust boundaries between them.
The actors
┌──────────────────────────────┐ composes unsigned actions / manifests
│ EMPLOYER │◄───────────────┐
│ ├─ Dashboard (web, no keys) │ │
│ └─ SIGNER (offline-capable, │── signed ──┐ │
│ holds the root key) │ artifacts │ │
└──────────────────────────────┘ ▼ │
KYB ATTESTER ────────────► ┌──────────────────────────┐ Payroll
binds pk ↔ legal entity │ REGISTRAR (hired service)│◄── connector
│ axum + SQLite (WAL) │ (per-run
┌─────────────┐ claim link, │ · per-employer log (BCS)│ idempotent)
│ WORKER │◄──────────────────►│ · epoch-scoped authority│
│ wallet PWA │ attestations, │ · type+rate-capped mints│
│ per-employer│ receipts │ · checkpoints → mirrors │
│ keys │ └──────────┬───────────────┘
└──────┬──────┘ │ revocation commitments,
│ ShareGrant (expiring link/QR) ▼ signed heads
▼ ┌──────────────────────────┐
┌─────────────┐ sealed bundle │ MIRRORS / WITNESSES (≥2) │
│ VERIFIER │◄────────────────────│ + Signer + wallets hold │
│ portal / │ 5-check predicate, │ signed log heads │
│ self-hosted │ offline-capable └──────────────────────────┘
└─────────────┘
| Actor | Code | Role |
|---|---|---|
| Employer | crates/tenure-signer, web/dashboard | Issues attestations about its own workforce. The Signer holds the root key and approves every signed action; the dashboard composes unsigned drafts and holds no keys. |
| Registrar | crates/tenure-registrar | A hired service that serializes attest/revoke operations for an employer, enforces delegation caps, stores derived credentials, and publishes signed heads. Single writer per employer. |
| KYB attester | (external) | Signs a KybAttestation binding employer_pk to a legal entity, with the methods used. Named on every verdict card. |
| Worker / holder | web/wallet | Holds per-employer keypairs, receives attestations + inclusion receipts, and signs ShareGrants — the consent record. |
| Verifier | web/verifier, web/verify-page | Runs the pure predicate over a sealed bundle and renders a verdict card. The self-hosted page is dependency-free and retains nothing. |
| Mirrors / witnesses | (external, mirror_urls) | Retain published signed heads. Two conflicting heads at the same (employer, seq) are a portable misbehavior proof. |
The two-app employer pattern
The single most important structural decision: the dashboard never holds a key and never signs anything. Root-key operations run in an independent Employer Signer — an offline-capable app that:
- generates and stores the employer root key (encrypted at rest),
- imports unsigned action drafts the dashboard composed,
- renders them human-readably (“You authorize registrar
tn1…to issue employment & income attestations for Acme LLC, max 500/day, epoch 1 from seq 1”), - signs on approval.
For bulk issuance the Signer ingests the raw batch file itself, computes the
aggregates and a deterministic, hash-seeded sample of rows locally, and refuses
to accept a summary from the dashboard. The aggregates ride inside the signed
tn-batch-v1, and the registrar cross-checks the signed summary against the
batch it received. A manifest hash alone is not HR safety; the Signer seeing the
real numbers is.
Trust model
| Actor | Trusted for | Not trusted for |
|---|---|---|
| Employer | Everything about its own attestations (they are its statements) | Other employers; the truth of the world — an attestation proves the employer said it, displayed as such |
| Employer Signer | Faithful display and signing of approved actions and batch manifests | (Residual) its own build/update channel — mitigated by reproducible, signed, pinned releases |
| Registrar | Liveness, serialization, policy enforcement, delivery, fee collection | Minting outside epoch-scoped type/rate caps; rewriting witnessed history without producing a conflicting signed head; attestation validity (that chains to the employer key) |
| KYB attester | Binding employer_pk ↔ legal entity (named, with methods, on every verdict) | Anything about workers; attestation contents. v1 sole-attester centralization is admitted; the long-term design is an attester taxonomy with verifier-owned trust lists |
| Wallet / holder | Holding per-employer keys; signing ShareGrants; retaining receipts | Anything else |
| Verifier app | Correct chain verification (open-source and self-hostable precisely so this is checkable) | Storing or re-sharing worker data beyond the grant |
| Mirrors / witnesses | Retaining published heads | Correctness of content (heads are self-verifying) |
Equivocation defense
Operation receipts and checkpoints place signed heads with the Signer, the
wallets, and at least two independent mirrors. Two registrar-signed LogHeads
with equal (employer_id, seq) and different head_hash are a portable
misbehavior proof. For employment records this protection is
two-directional: an employer or registrar cannot quietly backdate a hire or
scrub a tenure period after it was witnessed, and a worker’s receipts
survive the employer’s infrastructure dying.
What the registrar can and cannot do
A registrar is a commodity. It can stop serving, throttle, or lie about the current head — and none of that forges a credential or destroys one already held. It cannot:
- mint an attestation outside its delegation’s allowed types or rate cap — the verifier re-checks this and rejects the mint even though it is signed;
- rewrite witnessed history without producing a conflicting head anyone can detect;
- read claim values after mint — derive-then-purge leaves it only subject-encrypted blobs, a recovery escrow, and commitments (see Privacy);
- prevent an employer from switching to a different registrar — that is a signed epoch transition, and every previously issued attestation stays valid.
This is what “fireable commodity service” means in practice.