Imports & schedules
How data is imported from connected systems, the shared sync-schedule model with its 15-minute cadence floor, and how imports feed the Expected-vs-Actual model.
Imports are how the platform learns the current state of a connected system — who has accounts, which entitlements exist, and who holds them. Each system runs on its own independent schedule, and the same schedule primitive that drives imports also drives scheduled workflows. This page explains the import model, the schedule model, and how imported data becomes the Actual side of the reconciliation comparison.
What an import is
An import is a read from a connected system. It pulls the system's current objects — accounts, entitlements, and the assignments between them — into the platform so they can be governed. Imports are strictly read-only run types: syncing, health-checking, probing, and discovery. Writing back to a system (creating accounts, granting access) is a separate concern — a provisioning operation, tracked as a provisioning job — and is never part of an import.
The distinction matters: imports tell the platform what the system actually looks like right now. Governance decides what it should look like. Reconciliation compares the two.
💡 Tip
Business data — identities, accounts, entitlements, and assignments — must arrive through imports from live systems, never be seeded directly. Human-resources data flows in as identities; target systems flow in as accounts, entitlements, and assignments. Only configuration (connectors, account-type blueprints, policies, rules) is set up directly.
The sync-schedule model
Every connected system carries its own sync schedule, evaluated independently against that system's own last-run time. One system's cadence is never altered by another's. A schedule has a kind:
| Kind | Meaning |
|---|---|
interval |
Run every N minutes |
daily |
Run once a day at a set time |
weekly |
Run on chosen days of the week at a set time |
monthly |
Run on chosen days of the month (or an "nth weekday", e.g. the second Tuesday) at a set time |
manual |
Never run automatically — imports only when triggered by hand |
Each schedule carries its own timezone, and richer schedules can add a validity window (a start and end date), an intraday time window for interval schedules ("only within work hours"), and a "repeat every N" multiplier for cadences like biweekly or quarterly.
The 15-minute cadence floor
A sync interval may not be faster than 15 minutes. A value of 0 means manual-only and is always allowed; anything from 1 to 14 minutes is rejected. The reason is performance, not cost: the scheduler tick is about a minute and syncs within a tick run one after another, so a sub-15-minute cadence adds sweep load that slows other systems without any meaningful gain in freshness.
The floor is enforced centrally in the schedule parser, so it applies uniformly to every consumer of the schedule primitive. The configuration surface reflects this — presets start at hourly, and the custom input is clamped at 15 with a soft advisory in the 15-to-59-minute range: allowed, but not recommended.
The shared schedule primitive
The schedule model is a single shared primitive, not a per-feature reimplementation. Two real consumers use the identical schedule shape and the identical parser:
- Connector sync — a system's
sync_schedule, driving when it imports. - Scheduled workflows — a workflow's trigger schedule, driving when a
trigger_type=scheduledworkflow fires.
Because both go through the same parser, the 15-minute floor, the timezone handling, and every schedule kind behave the same everywhere. A multi-type timeline can therefore project the next fire times of both connectors and scheduled workflows onto one view — so "what runs when, across both imports and workflows" is a fact on screen rather than something inferred from a list of one-line summaries.
Event-triggered workflows are a separate mechanism (they react to an event, not a clock) and are outside the schedule primitive.
Ordering and dependencies between systems
Schedules are independent, but imports can declare a data dependency on another system — for example, an Entra sync that needs Active Directory to resolve samAccountName first. When two systems with a declared dependency both come due in the same scheduler tick, the platform orders them so the upstream system imports before the downstream one. A dependency only has teeth when both ends are due at once; it never changes either system's own cadence. Each system's import also runs in isolation — one broken system's failure is caught and logged, and the others continue.
When something else already owns the write
Two related questions come up as soon as a second system is connected, and both are about not fighting a sync that already exists.
Is there an upstream source? During onboarding a vendor-gated step asks whether another directory syncs into the system you are connecting — for Entra, whether an on-premises Active Directory feeds the tenant. Answering yes narrows what is imported to the objects that system actually owns, so the platform does not try to manage what the upstream sync already manages. Without that, two writers race over the same object and the loser is whichever ran last.
Who should receive a write? A sync relationship declares that system A is the source for system B, scoped to group memberships, identities, or both. When a grant or revoke on B matches the declared pattern, the platform does not write to B. It records the change and routes the action to the source side instead, where the existing sync will carry it downstream.
The canonical case is AD feeding Entra through Connect Sync: a group membership belongs on the AD side, and writing it directly into Entra would be undone — silently — the next time the two reconcile with each other. Declaring the relationship makes that explicit rather than leaving it as folklore held by whoever configured it.
Provenance is not one global authority matrix
An imported object retains the connector instance that observed it, and mappings declare how source fields enter the canonical model. Correlation keys, write mappings and upstream sync relationships each make authority explicit at their own boundary.
RapidValue does not currently claim one universal matrix that resolves every property conflict across every object and identity type. Evaluate authority per connector, mapping and operation. The distinction—and the safe conflict behaviour for API identity pushes—is documented in Source provenance and data authority.
How imports feed the Expected-vs-Actual model
An import produces the Actual state: exactly what exists in the connected system as of that run. The governance model produces the Expected state: what should exist, according to access grant policy matches, approved access requests, role-based assignments, and explicit keeps.
Reconciliation compares the two, per identity, per system:
- Actual comes from the most recent import.
- Expected comes from the governance model.
- Any difference is drift — an attribute changed by hand, an assignment that exists in the system but is not expected, or an account the model expects that is missing.
So imports are strictly upstream of reconciliation. They are not a competing view of access — they are the sensor that tells reconciliation what is really out there. A stale or failed import means reconciliation is comparing against old Actual data, which is why import health and schedules are worth watching. Throughout the product this comparison is labelled Expected / Actual.
One import at a time, and never wedged
A connector runs one sync at a time. Two imports of the same system racing each other read and write the same rows in an order neither controls, and the losing one silently overwrites the winner's work — so a manual "run now" while a scheduled run is in progress is refused rather than queued behind it, and the scheduler skips instead of stacking.
That guard creates a second problem that has to be solved in the same breath: if a sync process is killed halfway — a container restart, an out-of-memory kill — it leaves a run recorded as still running, and a naive guard would then block that connector's imports forever. There is no heartbeat to consult; the only thing known about a dead run is when it started. So a run still marked running long after any healthy sync would have finished is treated as dead, closed as failed with an explanation, and got out of the way. That clearing happens before the concurrency check, on the manual path and the scheduled one, and a background sweep does it too — so a wedged run clears even if nobody tries that connector again.
The pattern is worth naming because it generalises: a guard that can be poisoned by a crash is a guard that eventually becomes an outage. If you add one, you owe it a way out.
What a run tells you afterwards
A run used to report only its own diff — so many records read, so many changed. That answers "did it work", but not "is this system in the state I expect", and the second question is the one that catches problems.
Each completed run now also records where the system stands: how many accounts, entitlements and assignments it holds; how many of those accounts are correlated to a real identity; and how many carry a classification. Alongside that sits the change since the previous import, computed against the last completed run rather than against live data — so it reads as "since the last time we looked", which is the comparison a human is actually making.
Two things make that number trustworthy. A first import has no predecessor, so it shows no delta at all rather than presenting its entire contents as a sudden change. And computing any of this is best-effort: if the enrichment fails, the run still succeeds. Insight about an import must never be able to break the import.
Read together, those figures answer the questions that matter after a sync: a correlated-account count that stops tracking the total means new accounts are arriving unowned, and a sharp negative delta is either a real deprovisioning event or a filter someone narrowed by accident — either way, visible in the run rather than discovered a month later in a review.