Skip to documentation

SDK and error contracts

Swift API reference

Swift API reference SwiftPM package wisent errors (manifest at the repository root), library product WisentErrors , target under swift/Sources/WisentErrors . Platforms macOS 13 / iOS 13, zero dependencies. All refusal sentences below are th

Swift API reference

SwiftPM package wisent-errors (manifest at the repository root), library product WisentErrors, target under swift/Sources/WisentErrors. Platforms macOS 13 / iOS 13, zero dependencies. All refusal sentences below are the exact message strings.

Types

enum Code: String, CaseIterable, Sendable, Hashable, Codable

Cases config, auth, notFound ("not_found"), rateLimit ("rate_limit"), timeout, infraDown ("infra_down"), unknown — raw values are the wire strings, so an off-catalogue code is unrepresentable and Code(rawValue:) is the honest wire-boundary primitive (nil for anything unknown).

item contract
Code.retryExit: Int32 69 (EX_UNAVAILABLE)
severity: Severity derived, from the generated table
retryable: Bool, outage: Bool derived
httpStatus: Int the edge status
operatorSummary: String the catalogue's per-code sentence
exitCode(chosen: Int32) → Int32 retryExit when retryable, else chosen
Code.fromUpstream(status: Int) → Code exact matches, then the inclusive 500–599 range → .infraDown, else .unknown
Code.orFallback(_ text: String?) → Code the code, or .unknown for nil and anything off-catalogue; never fails

enum Severity: String, CaseIterable, Sendable, Hashable, Codable

Cases warning, error, critical.

struct Failure: Sendable, Equatable

failurePoint: String, code: Code, service: String are let; impact: String?, detail: String?, cause: [Failure], context: [String: String] are private(set) and filled through the builder methods. cause is an array holding at most one element — a value type cannot hold itself directly, and an array is the indirection; causedBy replaces, never appends. Derived: severity, retryable, outage.

enum Invalid: Error, Equatable, Sendable

case message
.failurePoint(point) failure_point "Not A Point" is not a dotted lowercase path
.empty("service") service must not be empty

Building

init(failurePoint: String, code: Code, service: String) throws

The strict builder. Trims failurePoint and service; throws Invalid.failurePoint when the point fails the grammar (isValidFailurePoint — lowercase dotted path, refusing a trailing -/_ and doubled separators) and Invalid.empty("service") when the service is blank.

Failure.orFallback(failurePoint: String?, code: Code, service: String?) → Failure

The salvage builder; never throws, takes optionals. An absent/empty point becomes unknown with wisent_errors.failure_point: absent in context; a malformed one is kept verbatim with wisent_errors.failure_point: malformed; an absent/empty service becomes unknown with wisent_errors.service: absent. The code cannot be off-catalogue — it is a Code; coerce untrusted text with Code.orFallback first (which is what the reporter's salvage overload does).

Builder methods (return copies — Failure is a value type)

method contract
impact(_ impact: String) trimmed; empty becomes nil
detail(_ detail: String?) trimmed to detailLimit (2000); empty/nil becomes nil
causedBy(_ cause: Failure) sets the failure underneath this one
withContext(_ key: String, _ value: String) inserts one context pair

Rendering

toJSON() → String

The envelope in the schema's key order, absent optionals written as null. Context keys are sorted before serializing so the bytes match the other three runtimes. Escaping is the same minimal JSON set (", \, \n, \r, \t, \u00XX for other controls).

render() → String

One line: <operatorSummary> — <whose><retry> <toJSON()>; em dash (U+2014), same derived wording as every runtime.

chain() → [String]

One row per cause-chain layer, outermost first: <failurePoint> [<code.rawValue>] <detail ?? "-">.

Trims

trimDetail(_ text: String?, limit: Int = detailLimit) → String

nil becomes empty, both ends trimmed, hard cut at limit (characters).

trimDetailAtWordEdge(_ text: String?, limit: Int = detailLimit, slack: Int = 24) → String

The same, cut back to the last space when one falls within slack characters of the bound; right-trimmed. Opt-in, because it changes emitted bytes.

Grammar helpers

isValidFailurePoint(_ point: String) → Bool, failurePointPattern (the regex as a string), fallbackCode (.unknown), detailLimit (2000).

WisentFailureReporter

The one transport in the repository (Report.swift), for desktop components. One rule carries the whole file: reporting must never fail the caller.

member contract
WisentFailureReporter.shared the process's reporter; init() is also public
report(_ failure: Failure) POSTs failure.toJSON() to <intake>/v1/failures with Content-Type: application/json and Authorization: Bearer <token>; never throws, never blocks — the POST runs in a detached task on one ephemeral URLSession with five-second request and resource timeouts, the response body is ignored, a non-2xx answer is swallowed
report(failurePoint:code:service:detail:impact:cause:) the salvage overload for crash handlers: code is a String coerced through Code(rawValue:) ?? .unknown, point/service coerce like Failure.orFallback

Configuration is the process environment, read at call time — the two variables and the loopback fallback are in configuration. With nothing configured, report is a no-op: misconfiguration ends the same way as a refusal or an unreachable intake.

Executed

Every sentence above is exercised by examples/swift-consumer.sh (a scaffolded consumer plus a toy intake capturing the POST); its captured output is in integrate/swift.