Enhancement Proposal

Proposal: The implementation arc — ordering of when to build what

This proposal gives the whole arc the Milestone-0 walking-skeleton proposal begins — the three large steps, the milestones between them, why they are in this order, what each retires in risk, and which are stopping or release points. It records direction and ordering, not dates: for an open-source project the sequence is the commitment and the timing is not. The why of the architecture lives in the ADRs and the architecture overview; this document orders the building of it.

Motivation

An identity platform can be built in many orders, most of them wrong. Bottom-up — the directory, then the protocols, then verification — defers the one thing that justifies the project, stateless edge verification independent of the strongly-consistent core (ADR-0001 rule 1), until last, and risks discovering late that the central claim is hard. This proposal commits to the opposite: a vertical slice that proves the differentiator first, then widens by risk (architecture §4.3; ADR-0010).

The ordering principle throughout is risk retired, not features delivered. A second principle makes the arc safe to pursue incrementally: every milestone is a coherent stopping point, and two are release points — so the project can pause, publish, or seek an operational owner at a real boundary rather than being all-or-nothing.

Design

The three steps

Step Goal Ends with
1. Prove the differentiator One login issued and verified at the edge with the core unavailable, shown under fault injection in simulation. The central claim is no longer a claim.
2. A real single-region issuer Widen the proven slice into a multi-tenant OIDC issuer on a real core, at enterprise scale. Release point: the first genuinely useful product.
3. The platform and global substrate Add the roadmap protocols (SAML, SCIM, MFA, federation) and the global edge fleet. Release point: the platform a provider builds on.

Step 3 is the longest and most trust-bound and should be pursued in full with a concrete operational owner committed to adopting and hardening it.

The milestones

Each carries: proves (what becomes true), retires (the risk removed), needs (what must exist first), done when (definition of done), and whether it is a stopping/release point. Every milestone's done-when also includes a security review of its new surface and the abuse-case tests for it (ADR-0027).

Prerequisite — the token and status-list formats, specified

  • Proves: the one contract that must outlive software is fixed before code is written against it (ADR-0003).
  • Retires: the risk of building verifiers against an unspecified token/credential layout and having to rewrite them — including the reserved seats (kid + per-kid alg binding, the format-version claim, the status-list reference, sid, amr/acr, cnf, the composite-alg hybrid seat) that cannot be added after verifiers exist (ADR-0003 decision 6).
  • Needs: nothing; the first work item.
  • Done when: the external OIDC-JWT layout (specs/vord-token-v0) and the status-list container (specs/vord-status-list-v0, with the ADR-0032 counter and the ADR-0043 sections) are specified in specs/, with the conformance-vector layout fixed; the first vectors land with vord-format so code and vectors cannot drift. The Troth SD-JWT-VC layout is specified when that primitive is built (it is not in the M0–M4 path). The format stays v0/unstable until a second independent verifier or a sustained run validates it.
  • Stopping point: no — a prerequisite, not a deliverable on its own.

M0 — Walking skeleton (Step 1)

  • Proves: rule-1 edge verification end to end — a token issued by Modgud and verified by Vör with the core unavailable.
  • Retires: the project's single largest risk, that the core-independence claim is hard to realise.
  • Needs: the format spec; the workspace scaffold and testkit (ADR-0013).
  • Done when: a relying party completes auth-code+PKCE and receives an OIDC JWT that verifies at the edge against published JWKS + a clock, and the verification completes correctly under DST with the core made unavailable — within the projection freshness window, failing closed past it — reproducible from a seed (ADR-0010). (Full detail: proposal 0002.)
  • Stopping point: yes — a credible, publishable proof-of-concept.

M1 — Production key custody and rotation (Step 2)

  • Proves: real KeyCustody (KMS/HSM; OpenBao is the audited self-hostable candidate, ADR-0008) with kid-addressed multi-key rotation, JWKS-as-edge-projection (ADR-0023), and the distribution key + projection freshness discipline (ADR-0043) — the JWKS and status list are signed by a non-token key and carry counter/iat/max-age from here on.
  • Retires: the risk in the most security-critical dependency; orphaned-token failure on rotation (V5); the stale-projection replay class (a replayed JWKS re-animating a killed key).
  • Needs: M0. Also the milestone where secret handling for non-signing secrets binds (proposal 0004: bootstrap credentials, hashed client secrets).
  • Done when: tokens are KMS-signed; rotation overlaps with no in-flight token left unverifiable; JWKS is an edge-cached projection under the ADR-0043 freshness rules.
  • Stopping point: soft.

M2 — Revocation propagation (Step 2)

  • Proves: the CQRS revocation path — signed status list (edge-cached) + NATS urgent push, with the edge's periodic refresh as the durable backstop (ADR-0005; the Wyrd-watch upgrade is a tracked cross-project ask, not a dependency).
  • Retires: the hardest primitive's propagation-latency risk (V2), without a hot-path core read.
  • Needs: M1. The observability capacity plane must exist here (proposal 0012): V2 is a statement about measured propagation lag, untestable without the revocation-lag and staleness telemetry.
  • Done when: an urgent revocation is visible at all edges within the freshness budget as measured by the freshness-plane telemetry; verification still reads only the projection (V1 re-run with revocation in the path, including the bounded-autonomy phase: fail-closed past max-age).
  • Stopping point: soft.

M3 — Authorization engine (Forseti) (Step 2)

  • Proves: the Authorizer over a Zanzibar engine with zookie-fenced read-your-writes (ADR-0006, ADR-0026).
  • Retires: the authz-at-scale risk and the trait-leak risk; the SpiceDB-vs-OpenFGA pick is made here under the ADR-0008 criteria. The engine's backing store is named here as the second consistency domain (ADR-0026).
  • Needs: M2. Three pulled-forward items land here because M4 cannot ship without them: the minimal ordering offset stamped on authoritative writes in both domains (ADR-0040 — the embryo of the M5 event stream, so M4 has a coherent joint-restore point); the in-sim Authorizer fake with real zookie semantics in testkit (ADR-0028 — V6/V9 are Tier-0 properties only if the two-domain interleavings are deterministically explorable); and the admin-authz cutover from the M0 static realm-admin policy to Forseti (ADR-0021).
  • Done when: a relationship decision evaluates over the graph; a just-granted permission is reflected when the decision presents a consistency token (V6); a step-up-then-authorize decision is correct across both domains via the composite token (V9) — in DST against the testkit fakes and in Tier 1 against the real engine; both domains stamp the ordering offset; the admin API is Forseti-governed with break-glass disabled (a tested property).
  • Stopping point: soft.

M4 — Multi-tenant / realm and scale (Step 2) ★ release point

  • Proves: tenant/realm as the shard+isolation+residency boundary on a real Wyrd (TiKV-backed) metadata core (ADR-0012).
  • Retires: the multi-tenant isolation risk and the MetadataStore-pluggability risk; validates 500K+ principals/tenant (V3) and per-tenant op-rate scaling (Wyrd ADR-0018 §4).
  • Needs: M3 — and a distributed Wyrd metadata deployment, the arc's one external schedule dependency (see the Wyrd-readiness note below).
  • Done when: tenants are isolated; no cross-tenant strong read on any hot path (V7) holds as a property test; per-tenant residency pins core data; the issuance + grant write rate scales per-tenant across both domains under a login-storm (V3) — the distributed write path, not only verification; the OIDC conformance suite passes (V8, scoped to the basic + config OP profiles, ADR-0025). Four release-gates join the definition of done because a multi-tenant release is not credible without them: the Vör crate split (the no-core-dependency claim becomes a crate-graph fact, ADR-0013); delegated administration (per-tenant/realm admin via Forseti, proposal 0016 — shipping multi-tenant with only the global break-glass admin would violate the rule-3 spirit); migration-lite (admin-API bulk import with legacy-hash verification, the M4-scoped half of proposal 0014 — an issuer no one can migrate onto is not "genuinely useful"); and the joint-restore runbook exercised across both domains at the M3 ordering offset (ADR-0040). The ★-gating rows of the attachment table below complete the definition — recovery, notifications, credential policy, and (for realms opening self-service registration) the deterministic attack-protection layer; everything tagged M4-era explicitly does not block the release.
  • Release point: end of Step 2 — a real, multi-tenant, enterprise-scale OIDC issuer, worth announcing and deploying even if Step 3 never follows. A maintainer / community security review plus the automated suite (CodeQL, OSS-Fuzz, the conformance run) precedes the release — no commissioned audit is assumed (ADR-0027). The release-integrity pipeline (signed artifacts, SBOM, SLSA provenance — proposal 0005, attached at M0) gates here: artifacts published at ★ are signed from the first release.

M5 — Identity event stream (CQRS) (Step 3)

  • Proves: the EventSink projections and replayable event stream; settles the Wyrd-ADR-0018 boundary in Vord's favour (ADR-0022).
  • Retires: the audit/billing-as-afterthought risk; ordering/replay ambiguity.
  • Needs: M4 (real multi-tenant events to order).
  • Done when: the stream is replayable; audit and billing read from it; revocation projections are a special case of it.
  • Stopping point: soft.

M6 — SAML 2.0 IdP (Step 3)

  • Proves: SAML SSO/SLO at Modgud with token-exchange to edge-verifiable JWTs (ADR-0017).
  • Retires: the SAML/edge-statelessness risk — the seam is proven by re-running the edge-independence test (V1) with SAML in the issuance path.
  • Needs: M4 (token exchange, sessions).
  • Done when: a service provider completes SAML SSO; the downstream artifact is an edge-verifiable JWT; V1 still holds.
  • Stopping point: soft.

M7 — Provisioning and strong auth (Step 3)

  • Proves: SCIM provisioning with the deprovision→revocation join (ADR-0018), MFA/WebAuthn with edge-enforced assurance (ADR-0020), and upstream federation (ADR-0019).
  • Retires: the lifecycle-gap risk (a deprovisioned user whose live tokens linger) and the MFA-enforcement-on-the-hot-path risk.
  • Needs: M5 (the event stream) and M6 (federation shares the SAML/exchange seam).
  • Done when: a deprovisioned principal can no longer authenticate at the edge within the freshness budget; an MFA-required operation is enforced by Vör reading the token's amr/acr with the core unavailable.
  • Stopping point: soft.

M8 — Multi-region edge fleet and hyperscale (Step 3) ★ release point

  • Proves: worldwide stateless Vör edge nodes, regional Modgud, the core on Wyrd multi-region (ADR-0024).
  • Retires: the final risk — that the guarantees hold single-region but not globally; validates millions of CIAM users across regions (V4) and 500K+/tenant.
  • Needs: M7.
  • Done when: edge verification is global and core-independent across regions; revocation propagates to all regional edges within budget; the write path sustains the millions-per-realm registration/login rate across regions (V4).
  • Release point: end of Step 3 — the global identity substrate. A maintainer / community security review plus the automated suite precedes the release; a sponsored third-party audit is welcome if funded, never required (ADR-0027).

Dependency graph

%% The implementation arc — mostly linear, the DST harness growing throughout graph LR spec["format spec"] --> M0 M0 --> M1 --> M2 --> M3 --> M4 M4 --> M5 --> M6 --> M7 --> M8 M4 -.->|release| R1["★"] M8 -.->|release| R2["★"] dst["testkit / DST"] -.-> M0 dst -.-> M8

The arc is mostly linear (each milestone validates against the previous one's result). The testkit DST harness attaches at M0 and is extended at every subsequent milestone — a growing dependency, not a one-time build (ADR-0002). Genuine parallelism appears once there are multiple contributors; M5 (event stream) and M6 (SAML) have the most independent surface.

Releases ride the milestones

Every milestone cuts a tagged release under the release plan (proposal 0029): 0.x minors through M3 (tagged, unsupported, may break anything), 1.0.0 at M4 ★ — release-candidate soak first, and the specs stamp v1 in the same cut (ADR-0003's sustained-conformance criterion is satisfied by V8) — then minors per milestone, with the M8 ★ announcement deliberately decoupled from its SemVer digit. Artifacts are produced only by the proposal 0005 pipeline; support is latest-minor-only until an operational owner commits (the same trigger as Step 3). The arc orders the work; 0029 says what shipping it means.

The Wyrd-readiness dependency, stated

Wyrd is the arc's one external schedule dependency, and each milestone needs a different amount of it. M0 needs no Wyrd at all (the embedded in-memory core behind the CredentialStore seam). M1–M3 Tier-1 integration needs the single-process Wyrd metadata deployment that exists today — Wyrd's own M0/M1 are complete and its MetadataStore (narrow KV, atomic preconditioned commit) is exactly the primitive the directory write needs. M4 needs what does not yet exist: a distributed (TiKV-backed) Wyrd deployment — Wyrd's own M2+. Two hedges keep this coupling from becoming a blocker: the directory sits behind Vord's own seam, and the named interim backend is TiKV directly — the very substrate Wyrd's distributed profile targets, CNCF-graduated and ADR-0008-clean, offering the primitives the core needs today (transactional preconditioned commits, PD placement rules for per-tenant residency, TSO timestamps to mint the fence) — so a CredentialStore adapter against raw TiKV is a composition change if Wyrd's schedule slips (rule 4 keeps the accommodation on Vord's side); and the revocation backstop is poll-based by design (ADR-0005) — the Wyrd watch API is an upgrade, not an assumption, tracked as a cross-project ask against Wyrd's roadmap.

Naming the fallback also states the bar Wyrd is held to: Wyrd holds its seat by the metadata-model layer it provides over the raw substrate — the tenant→keyspace→placement management, the home-zone linearization semantics, the carryable meta:version fence contract, the (future) watch, and the sim-faithful metadata logic testkit can embed (ADR-0028). If at a milestone gate running Wyrd adds operational surface without delivering that layer, the seam makes the TiKV adapter the honest choice — the sibling coupling is a bet Wyrd earns per milestone, not a sunk cost Vord defends. (The same bar governs the reserved authorization-store collapse, ADR-0026 §4, which is substrate-agnostic by design.)

Deferred-with-reserved-seats

Built later, but their hooks exist from the relevant milestone because retrofit is expensive: biscuit attenuation (ADR-0003); DPoP/PAR/FAPI token-shape seats (ADR-0014, ADR-0025); the amr/acr and sid claims (ADR-0020, ADR-0044); the status-list reference claim and the projection-freshness fields (ADR-0032, ADR-0043); the EventSink emit-points with versioned event schemas (ADR-0022); the custom-domain iss/JWKS seat (proposal 0007 — decided before passkeys bind to realm origins, ADR-0020); billing/metering as an event projection; the admin web UI (ADR-0021).

Product features attach to milestones — they are not milestones

The competitive product surface layers on the milestones rather than reordering the arc: each proposal attaches where its dependency lands, and none retires a load-bearing risk of its own. The arc orders the risk-retiring core; features ride it. The blanket "most from M4" of an earlier draft was wrong in both directions — some proposals are verification dependencies of early milestones, others cannot land before Step 3 — so the attachment is now explicit (and recorded as milestone: front-matter on each proposal).

An attachment comes in two strengths, and the table says which: gates ★ — the release point does not ship without it; and M-era — the feature becomes buildable at that milestone and lands before or after the announcement without blocking it. The distinction protects the release points: a stopping point that accretes ungated feature work stops being a stopping point.

Proposal Attaches Why there
0004 secret handling M1 Binds with production custody: bootstrap credentials, and hash-only client secrets are a one-way door that must be right before confidential clients exist.
0005 build & release integrity M0, gates M4 ★ Actions pinning/branch protection are M0-cheap; artifacts cannot be retroactively signed, so the pipeline must predate the first release.
0012 observability M0–M2 A per-milestone verification dependency like testkit: V2 (revocation lag) is untestable and V3/V4 unprovable without the freshness/capacity planes.
0006 resource-exhaustion hardening per-control: M0 / M6 / M7 Argon2id cost-before-auth ships with password login (M0); XML hardening with SAML (M6); SCIM stream limits with M7. Owns the rate-limit umbrella throughout.
0020 accessibility M0+ The axe-core gate exists from the first shipped UI (the M0 login page), not retrofitted at M4.
0007 hosted login & branding split: M0 ceremony / post-M4 branding The minimal hosted ceremony is on the M0–M4 conformance path; theming, localization, and custom domains layer after ★ — but the custom-domain iss/JWKS seat is decided at M4 (and before passkeys bind, ADR-0020).
0014 user migration split: M4 import / M7 JIT-federated Bulk import + legacy-hash verification is an M4 release gate (adoption blocker), with resumable-job/dry-run mechanics sized against V3; SCIM- and federation-driven migration follows its M7 dependencies.
0016 delegated administration M4 (release gate) Per-tenant admin via Forseti (available from M3); multi-tenant ★ with only the global break-glass admin would violate the rule-3 spirit.
0011 notification delivery ≤ M4 — gates ★ A dependency of recovery (0003) and of any CIAM realm: no verified email/SMS channel, no credible self-service.
0003 recovery & contact verification M4 — gates ★ Modgud ceremonies on the 0015/0016 seams; needs 0011.
0013 credential policy & breached-password M4 — gates ★ Realm policy over the M0 password verifier; lockout counters fold into 0006's umbrella.
0008 claims customization M4-era Declarative mapping on the issuance path; the code tier is ADR-0029's.
0010 self-service account management M4-era Profile/session/consent surfaces over 0016/0037/0044.
0015 B2B organizations split: M4–M5 members+invites / M7 per-org connections The org sub-level rides the tenancy model; per-org IdP connections need federation (M7).
0009 webhooks & subscriptions M5 A delivery projection of the event stream (ADR-0022/0029) — it cannot precede the stream.
0018 admin console & reporting M5+ A client of the admin API over the M5 analytics projections; 0012 owns emission, 0018 presentation.
0019 billing & usage metering M5+ Counters as stream projections.
0017 directory synchronization M7+ Inbound sync composes with SCIM/provisioning; the operator-network agent needs its own ADR before build.
0021 attack protection M4 deterministic (gates ★ for realms opening self-service) / M5+ scoring Self-service registration cannot open without bot/fraud controls — a workforce-only ★ may ship without it; the risk-pipeline upgrade needs the M5 stream (ADR-0031).
0022 token vault M7+ Stores and brokers upstream-IdP tokens — meaningless before upstream federation (ADR-0019) lands.
0023 configuration-as-code M4-era A client of the stable admin API (ADR-0021); environment promotion presumes the multi-tenant model.
0024 integration catalog M6–M7 App templates are mostly SAML/OIDC/SCIM presets — the protocols they preset must exist first.
0025 compliance & residency enablement M5+ Evidence exports are projections of the event stream; residency mechanics exist from M4, the product surface follows the audit plane.
0026 admin impersonation M6 Its mechanism is the RFC 8693 exchange, which is built with the SAML milestone (ADR-0017) — and its defense is the audit trail, queryable from M5; both bounds land it at M6.
0027 SDKs & developer experience M4-era The release's adoption path: the local-verifier SDK and one CI-tested quickstart accompany ★; the full language matrix and generated clients follow without gating it.
0028 authenticator app & push MFA M7 Rides the strong-auth milestone's seams (0015 methods, 0020 assurance, 0011 channels); the temporary access pass ships with it as the passwordless-onboarding credential.
0029 release plan & versioning policy pre-M0; first tag at M0 Every milestone cuts a release under its version map; 1.0.0 at M4 ★ is gated on the specs stamping v1; the patch path is exercised before it is needed.

Alternatives considered

  • Bottom-up (directory and protocols first, verification last): rejected — it defers the differentiator and the largest risk to the end.
  • Specify everything up front: rejected — spec-first is confined to the token/credential format, the only contract that must outlive software (ADR-0003); the rest is discovered correctly by building.
  • Date-driven roadmap: rejected — an open-source project cannot honestly commit dates this early; the arc commits to order, not schedule.

Graduation criteria

Accepted (moves draft/ → accepted/) when the three-step shape and milestone ordering are agreed and no milestone's needs edge is disputed. Each milestone is "done" in the roadmap sense when it has a tracking issue and the definition of done above; the arc is superseded by a revised arc if an ordering is found wrong in practice.

Backward compatibility

  • Token/credential format: fixed before M0 but v0/unstable; no tokens to migrate until it is stamped stable.
  • Reserved seats are honored from the milestone where retrofit is expensive, not when the feature ships (the list above).
  • Public API / deployments: none until the Step-2 release (M4); nothing to stay compatible with before then.

Open questions

  • Does Step 3 begin only once a concrete operational owner is committed, or is a reference multi-region deployment pursued to demonstrate the full design?
  • At which milestone does the token/credential format graduate from v0/unstable to a stamped-stable spec — when a second, non-reference verifier validates it (ADR-0003)?
  • Whether CIAM requires any principal-model extension that policy cannot express (ADR-0011) — narrowed by ADR-0037 (consent is decided); what remains is marketing-preference state and anonymous→known promotion, to be settled before the directory schema is stamped (a hard gate at M4).
  • Wyrd's distributed-deployment (its M2+) timing relative to Vord's M4 — the one cross-project schedule question; the hedges are recorded in the Wyrd-readiness note above.