Skip to main content

OctetVerdict

The outcome of a predicate call. Returned by isWithin, isOutside, contains on OctetSdk.loc.

Shape

public struct OctetVerdict: Sendable {
public let result: Result
public let reason: ReasonCode
public let message: String
public let proof: LocationProof?
public let validity: Interval?
public let queriedAt: Date
public let confidence: ConfidenceSummary

public enum Result: Sendable, Hashable {
case yes, no, indeterminate
}

public enum ReasonCode: Sendable, Hashable {
case ok
case noFix
case futureTime
case staleFix
case noProofAtResolution
case attestationFailed
case mockLocationDetected
case sdkNotRunning
case notYetReleased
}
}

Field invariants

  • proof is nil/null iff result == .indeterminate/INDETERMINATE. Enforced as a precondition / require at construction. A YES or NO always carries a proof. An INDETERMINATE never does.
  • validity is non-nil exactly when proof is non-nil. Both move together.
  • queriedAt is the atTime that was passed in. Echoed back so callers do not have to thread it themselves.
  • confidence is always populated, even for INDETERMINATE (with an empty summary in that case).

result. The trichotomy.

ValueMeaning
.yes / YESPredicate holds. Proof attached.
.no / NOPredicate provably does NOT hold. Proof attached.
.indeterminate / INDETERMINATESDK cannot answer. See reason.

Never collapse .indeterminate to .no silently. See Verdicts for the rationale.

reason. The ReasonCode.

CodeResultMeaning
ok / OKYES or NOProof covered atTime. Predicate evaluated cleanly.
noFix / NO_FIXINDETERMINATESDK started but no fix yet (also: running on simulator / emulator).
futureTime / FUTURE_TIMEINDETERMINATEatTime is in the future beyond ±2 s clock-skew tolerance.
staleFix / STALE_FIXINDETERMINATEatTime falls outside the validity window of any cached proof.
noProofAtResolution / NO_PROOF_AT_RESOLUTIONINDETERMINATECached proof is too coarse for the query (country proof, city query).
attestationFailed / ATTESTATION_FAILEDINDETERMINATEPlay Integrity / App Attest verdict not COMPLIANT.
mockLocationDetected / MOCK_LOCATION_DETECTEDINDETERMINATEOS flagged mocked location.
sdkNotRunning / SDK_NOT_RUNNINGINDETERMINATEOctet.start(...) was never called or session ended.
notYetReleased / NOT_YET_RELEASEDINDETERMINATEPredicate path declared by the API but not wired in this SDK build.

message. For humans only.

message is a free-form string useful for log lines and debug UI. Do not parse message for control flow. Parse reason instead. The text is intentionally informal. The SDK reserves the right to refine it across versions.

proof. The cryptographic witness.

LocationProof is the signed protobuf that a verifier checks against Octet's public keys. Its full shape is part of the protocol, not the SDK's public surface. See Serialization for the v1 alpha caveat about how LocationProof is currently rendered through .toJson().

For most integrators the proof is opaque. Forward it to your verifier as-is.

validity. The proof's temporal window.

The interval over which the underlying proof answers the predicate as stated. Not "how long the verdict will stay true". See Time Semantics.

public struct Interval: Sendable, Hashable {
public let from: Date
public let to: Date
}

Inclusive-inclusive, from <= to.

confidence. The score and flags.

ConfidenceSummary surfaces the SDK's overall confidence score and a list of flags (mock-location detected, VPN active, GNSS anomaly, and so on). A strict caller can treat a low-confidence YES as effectively INDETERMINATE:

let strictYes = verdict.result == .yes && verdict.confidence.overallScore > 0.8

The SDK never applies this collapse for you. The policy lives on the caller side.

See also