Provisioning

Intent, versioned. State, converged.

Describe the desired state. Owlie generates the plan. Retries are idempotent. Overlapping changes converge by version, not by timing. Pre-flight reads protect against duplicate accounts. Failures produce a structured journal. Recovery is a single button.

Operation lifecycle

Five beats from intent to applied.

A provisioning operation is the unit of work. It arrives from any of a dozen origins — an approved request, a direct assignment, a policy-driven change, a sync observation, a schedule, among others — and it carries a typed action, a validated payload, and an idempotency key. Here's what happens next.

  1. 01

    Intent received.

    An operation arrives typed and validated: provision, update attributes, add entitlements, disable, revoke. The payload is checked against a per-action schema before the operation is accepted — malformed requests fail fast at the caller, not deep inside reconciliation. The idempotency key collapses retries from a flapping service onto the same record.

  2. 02

    Desired state resolved.

    The Resource's provisioning profile, the identity's attributes and roles, and the operation's payload compose into a versioned desired state. Attribute writability, requiredness, and immutability are enforced at resolve time. Connector-backed Resources validate against the connector's declared account schema and entitlement catalog. The assignment's desired_version advances only when the state actually changes.

  3. 03

    Plan generated.

    Owlie computes the minimal set of steps to reconcile observed state to desired — create, lifecycle change, attribute set, entitlement add/remove. When the local snapshot is missing or stale, a pre-flight read decides whether to create or adopt. After adoption, account creation cannot re-enter the plan — enforced by construction and backstopped by a runtime guard that rejects any violating plan.

  4. 04

    Reconciliation.

    Steps run against the chosen fulfillment path. Connector errors are translated from the connector SDK's taxonomy into a stable, structured shape with retryability already decided: auth errors don't retry, rate limits always do, others follow connector guidance. Prior successful steps are not re-run on retry within the same desired version.

  5. 05

    Apply and project.

    On success, applied_version advances, the observed account state is snapshotted, and graph facts are projected into the shared identity graph — all in the same transaction. What we think we applied cannot drift from what we recorded as applied. Callbacks fire on terminal states; real-time events move the operation through the UI.

Where the steps land

One contract. Four fulfillment paths.

Every path hits the same state machine, writes to the same journal, emits the same callbacks, and projects into the same graph. The difference is only where the work physically runs.

Automated connector.
Native connectors run the steps. Diff-minimal plans compute the smallest set of writes needed to reconcile. Connector errors map to the shared taxonomy.
Manual ticket.
When a Resource is fulfilled by a user or group, Owlie opens a ticket and parks the operation. Ticket outcomes — approved, fulfilled, rejected, reassigned — feed the same state machine as connector runs. Same audit trail, same callback contract.
Function.
Customer TypeScript runs the fulfillment step. Sandboxed, per-version secrets, allowlisted outbound.
Virtual.
Resources whose state lives entirely inside Owlie — grants that don't have an external target. Useful for ownership, membership, or internal entitlements that never leave the system.

Attribute resolution

The manager field, in the target's own format.

Desired state isn't only literal values. A resource profile maps attributes to the identity model — and the hard ones are references to other accounts, or values that have to keep changing after the account exists. Owlie resolves them in the target's native format, in any order, and keeps them true. The classic "provision the manager before the report" problem disappears.

References, in native format.
A manager isn't a name — it's that manager's account identifier in the target system's own wire format, like an Active Directory manager DN. Map an attribute to an identity relationship and Owlie resolves the referenced account into the correct target-specific value. Active Directory ships the manager mapping by default; the same mechanism works for any connector attribute that declares itself a reference — including a reference to an account on a different system.
Onboard in any order.
Provision a report before their manager's account exists and the reference doesn't fail or silently drop — it defers, then backfills automatically once that account lands, whether it arrives by provisioning or by sync. Batch onboarding runs in any order, across systems, with no dependency ordering and no deadlock on reference cycles. A profile preview surfaces deferred references as explicit "will backfill" warnings, not opaque gaps.
Attributes that stay true.
Mark a mapping keep_in_sync and it keeps pushing. When a title, department, or manager changes in the identity source, Owlie re-evaluates that one attribute and pushes the changed value to the already-provisioned account — no re-provision, no scheduled reconcile job, no per-connector drift code. Opt-in per attribute: anything unmarked never drifts, and credentials never sync out.
Access that starts later.
An assignment can carry a future start_time, not only an expiry. The account waits in a scheduled state with no connector work until the start arrives, then provisions the latest accumulated desired state. Expiry is swept before activation, so a window missed by a late alarm is never provisioned stale.

Timed sequences

A revoke can take months.

A provisioning profile can render one operation as a sequence that unfolds over time: fixed waits, event pauses that hold until an external system or an admin resumes, and follow-up operations against the same assignment. The canonical case is offboarding done right — one revoke decision, played out as a compliant, staged teardown authored on the resource profile instead of stitched together from tickets, reminders, and outside schedulers.

  1. 01

    Disable now

    The revoke disables the account immediately. The operation completes and its callback fires — the remaining steps continue as a standing schedule against the assignment.

  2. 02

    Wait 30 days

    A fixed pause — anything from a minute to about a year — holds while the account sits disabled and recoverable.

  3. 03

    Archive

    A connector archive step runs against the target system.

  4. 04

    Wait 60 days

    Another pause. Each step proceeds only if the assignment still looks the way the sequence assumed.

  5. 05

    Delete

    A follow-up revoke deletes the account and frees the single-assignment slot for a future rehire-as-new-account.

Guard-first, so a rehire wins.

Each step after a wait proceeds only if the assignment still looks the way the sequence assumed. Rehire someone mid-sequence and the pending schedule cancels cleanly — a disabled account is re-enabled with its history intact, and the newer intent wins.

Pause on an external gate.

A provision can park on an event pause — wait_for_resume — until a third-party identity-proofing callback or an admin resumes it, with a bounded timeout and a defined fail-or-continue outcome. Externally gated onboarding becomes a property of the profile, not a scheduler someone has to build and babysit.

Convergence

Retry is a single button.

Every operation carries an idempotency key and a target version. Retry is one entry point — safe to call repeatedly, against any stuck state. Prior successful steps are not re-run. Concurrent changes converge by version, so rapid-fire operations on the same assignment resolve to a single coherent state instead of racing. When an account has already been adopted, the plan cannot re-attempt creation. Background scans close operations that the fast path missed, re-enqueue work stranded past lease expiry, and fail operations whose reconciliation has terminally errored. These are architectural invariants, not configuration knobs.

Evidence

Every attempt, on the record.

Every reconciliation attempt writes a per-step row with status — started, done, failed, superseded — a timestamp, and a structured error payload if it failed. Steps that previously succeeded are durable across retries. When a retry picks a different plan, obsolete rows are marked superseded, not deleted. Actual-state snapshots are persisted alongside the applied version in the same transaction. The journal is the audit log, the debug log, and the correctness proof in one.

Approval isn't the end of the story.

Early access is open. Bring your real provisioning scenarios — the retries, the overlaps, the duplicate-account near-misses.