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 an approved request, a direct assignment, a role change, or a revocation, 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. This is an invariant, not a check.

  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.

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, a duration, 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.