Skip to content

The asynchronous-outcome audit

Several Fabric APIs document two outcomes: a synchronous answer and a 202 Accepted carrying an operation to poll. Real Fabric uses both. The emulator produced only the synchronous one on three surfaces, which is the worst direction for a divergence to point — emulator-green, tenant-broken — and the failure is silent rather than loud.

This doc records the audit: the rule that makes it repeatable, what was checked, what was found, and what was deliberately not claimed.

The first pass read Responses tables one API at a time. That works and does not scale. The pattern that emerged is much cheaper:

Every surface that answers 202 says so in its description, in these words: “This API supports long running operations (LRO).” Every surface that does not, does not.

So the sweep is a search, not a reading exercise: find that sentence in the REST reference, then check the emulator can produce both outcomes for each hit. That is an instruction someone who has never done this can follow.

It also bounds the problem. The three defects below were anomalies, not the front of a queue — six further surfaces were checked and every one was clean.

A client that meets only the synchronous answer never exercises its own polling path. Then a tenant answers 202 and the failure is quiet:

APIwhat the client readswhat it concludes
getDefinitionthe 202 body, which is nullthe item has an empty definition
createItembody["id"] on a 202None["id"] — a crash three calls downstream

Neither reports an error. The first is the dangerous one: an empty definition is a plausible answer, so nothing looks wrong.

Both were found by calling a real tenant, not by reading code — getDefinition here, createItem independently while running examples/medallion-pyspark against real Fabric.

SurfaceDocumentedEmulator wasFix
getDefinition200 / 202200 onlyFABRIC_FORCE_LRO
createItem201 / 202201 unless a definition was suppliedFABRIC_FORCE_LRO
git/initializeConnection200 / 202200 onlyFABRIC_FORCE_LRO

createItem was the sharpest: Create Warehouse documents 201 and 202, a tenant answered 202, and the same page says it “does not support create a warehouse with definition” — while the emulator went async only for a definition-bearing create. So the one item type measured asynchronous was the one type guaranteed synchronous here.

git/initializeConnection is the only one of the three whose operation carries a real result body, so it also covers the case where the async answer must hand back the same object the synchronous one did.

The lever is off by default: the synchronous answers are equally legal and are what most calls see. The point is that the other half is reachable at all — the same idea as FABRIC_LIST_PAGE_SIZE=2 forcing the continuation-token loop.

Recorded so nobody re-checks them. A negative result is worth as much as a positive one when the value of a sweep depends on knowing its coverage.

SurfaceDocumentedEmulatorVerdict
git/connect200 only200clean
git/disconnect200 only200clean
admin/domains/{id}/assignWorkspaces200 only, even in bulk200clean
updateDefinitionLRO202 alreadyclean
commitToGit, updateFromGitLRO202 alreadyclean
capacity assign / unassignLRO202 alreadyclean
workspace identity provision / deprovisionLRO202 alreadyclean
deployment pipeline deployLRO202 alreadyclean
item job instancesLRO202 alreadyclean

Mirroring is a special case: Update Mirrored Database Definition supports LRO, but it routes to the generic updateDefinition, which is already asynchronous — so it is covered without being a separate fix.

Gaps, which are a different thing from divergences

Section titled “Gaps, which are a different thing from divergences”

Documented LROs the emulator does not implement at all. These are not wrong shapes, and a sweep for wrong shapes will not find them:

  • Load Table (…/lakehouses/{id}/tables/{name}/load)
  • sqlEndpoints/{id}/refreshMetadata
  • Mirroring start / stop / status (startMirroring, stopMirroring, getMirroringStatus) — the emulator has its own refreshMirror instead

This is not a proof that no fourth divergence exists. It is a record of what was checked, by a rule that anyone can re-run. Applying the rule to the whole reference — rather than to the surfaces this emulator already implements — is the obvious next pass, and it has not been done.