GeoLeaf Core API - v3.19.0
    Preparing search index...

    Type Alias QuarantineReason

    QuarantineReason:
        | "deletedOnServer"
        | "layerNoLongerWritable"
        | "rejectedByServer"
        | "notImplementedByServer"
        | "retryBudgetExhausted"
        | "authRequired"
        | "dialectNotSupported"

    Why an entry was set aside instead of replayed or dropped.

    Type Declaration

    • "deletedOnServer"

      The server deleted the entity while it was being edited locally.

    • "layerNoLongerWritable"

      The layer has no write target when the entry is pushed: its write block is absent, switched off, or carries no endpoint.

      ⚠️ edition is not read again: an edit captured while the layer allowed it is still sent once the permission has been withdrawn from the profile. What refuses it then is the server.

    • "rejectedByServer"

      The push was refused by the server for a reason replay cannot fix.

      ⚠️ NARROWED on 09/08/2026, and the previous width had a measured cost. This member used to name EVERY non-409/non-404 failure, transient server outages included: pushOne had a single branch for the whole spectrum. Since this reason is excluded from REQUEUEABLE, a 503 during maintenance spent the replay budget and then left the capture unreplayable — its only remaining exit being destruction. It now covers 4xx refusals only, 404 and 501 excepted: malformed request, missing right, verb not allowed, unprocessable entity. A server outage is retryBudgetExhausted; an unimplemented verb is notImplementedByServer.

      It also names a creation the server did not write: answered 409, or acknowledged with an empty array, while the re-read through the client identity finds no row. The status that travels with the entry is then the one of that answer — a 2xx in the second case.

    • "notImplementedByServer"

      The server does not implement the verb — HTTP 501.

      🛑 ADDED on 09/08/2026, and the asymmetry it closes is the reason it exists. An unimplemented verb on the CLIENT side (the rest dialect, push-engine.ts) already fell through to retryBudgetExhausted and was therefore replayable; the same fact reported by the SERVER landed on rejectedByServer and was not. Same fact, opposite outcomes.

      It is set IMMEDIATELY — replaying a verb the server does not know only waits three times, the same argument as deletedOnServer — and it IS replayable: the lifting condition is the server being upgraded, which no local check can observe, so it is entrusted to the operator exactly like retryBudgetExhausted.

    • "retryBudgetExhausted"

      The replay budget ran out — the entry failed MAX_REPLAY_ATTEMPTS times without the server ever answering in a way replay could act on.

      ⚠️ ADDED on 05/08/2026, and it was missing for a precise reason. The three motives above all name a CAUSE observed on the server or layer side. An exhausted budget is not one: the server may never have answered. Reusing rejectedByServer for a network timeout would have been a lie the code itself detects — push-engine already distinguishes networkError from rejectedByServer.

      ✅ It also carries transient server failures since 09/08/2026 — 500, 502, 503, 504, 408, 429. Its sentence already covered them ("without the server ever answering in a way replay could act on"): upstream classification just was not sending them here.

    • "authRequired"

      The session is over — the server answered 401 on a write. A 403 says the identity is known and lacks the right, which no sign-in changes: it stays rejectedByServer.

      🛑 ADDED on 02/09/2026, and it closes the same asymmetry as notImplementedByServer. A 401 landed on rejectedByServer, the one motive this contract defines as "a reason replay cannot fix" — while an expired token is the exact case replay DOES fix, as soon as the operator signs back in. A field capture was therefore set aside with destruction as its only contractual exit, for a cause that lifts by itself.

      ⚠️ It names a state of the SESSION, not a refusal by the server, and that is why it is not a sub-case of rejectedByServer: in the connector's token mode the 401 the drain sees is even SYNTHETIC — the interceptor produces it after failing to renew. Same status code, opposite meanings; the motive follows the meaning.

      It is set IMMEDIATELY — replaying with a dead token only waits three times, the argument of deletedOnServer and notImplementedByServer — and it IS replayable: the lifting of the cause is a new sign-in, which nothing in the core can observe (it knows nothing of the connector), so it is entrusted to the operator exactly like retryBudgetExhausted.

    • "dialectNotSupported"

      The layer declares a write dialect the core does not speak — rest today.

      🛑 A CLIENT-SIDE HOLE, AND IT USED TO BE SILENT. The drain refused the dialect by name but returned an ordinary failure: the entry spent its replay budget against a hole no replay can fill, then landed on retryBudgetExhausted — a motive that says "the server never answered", when no request had ever been made. The operator could requeue it, and it went round again.

      It is set IMMEDIATELY, like layerNoLongerWritable, and its lifting is just as OBSERVABLE: the layer's declaration changes, or it does not. That is why it is requeueable and yet verified — see write/quarantine-api.ts.