# Reaching and keeping `hardware` trust > Last updated: 2026-10-13 How to check provider verification and retain legacy `hardware` trust where eligible. New providers require macOS 27 or later and current qualified App Attest authorization; a `hardware` label is not required for that path. Only the frozen linked account/SE-key/previously MDM-verified device cohort may temporarily use legacy verification. For operators; the mechanism — what each layer proves, the grant and loss conditions, the routing gate, and the code map — is in [`../architecture/security/attestation.md`](../architecture/security/attestation.md) and is not restated here. Current backend behavior is defined by the [platform's latest default branch](https://github.com/Layr-Labs/darkbloom-platform/tree/master). Immutable platform links below preserve evidence snapshots, not current source or proof of deployment. The connected coordinator's verdict remains authoritative for serving and MDM-removal readiness. Optional [App Attest shadow checks](../reference/app-attest-shadow.md) run in the background. Shadow results do not change these enrollment requirements or your existing trust eligibility. Version/cohort controls protect older clients; see the [rollout procedure](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/operations/app-attest-rollout.md). App Attest replies and received grant updates can progress while model loading is suspended. A local Apple success still does not establish coordinator acceptance; use the current coordinator verdict when diagnosing expiry. See [provider connection control](../architecture/security/attestation.md#provider-connection-control). A signed version is registered as an official build by trusted release CI before publication. Its durable identity survives coordinator restarts. No per-release hardware qualification or manual approval is required. Runtime serving still requires actual Apple enrollment/assertion verification matching the official code/runtime hashes; registration and notarization cannot substitute for those checks or undo permanent revocation. Recurring receipt readiness is a separate platform-owned reward/MDM-removal requirement, not a basic-serving gate. Missing official identity keeps serving pending, not a reason to delete credentials or replace an employer profile. See the [current build-registration contract](https://github.com/Layr-Labs/darkbloom-platform/blob/master/docs/reference/provider-authorization.md#durable-build-qualification); the [earlier qualification contract](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/reference/provider-authorization.md#durable-build-qualification) is retained as historical evidence. Account erasure also clears delayed account-specific proof writes and frozen legacy-MDM membership; [shared-device cleanup](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/architecture/account-erasure.md#shared-machines-and-shared-keys) retains another live account's device evidence. Unshared APNs tokens and pending challenges are removed from the coordinator's runtime cache too; stale replies cannot restore them ([identity cleanup](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/architecture/security/identity-binding.md#account-erasure-and-apns-runtime-state)). Autopilot earnings-floor qualification is a separate historical check: a new authorization does not qualify a declaration received before that grant. See the [reward policy](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/reference/pricing-model.md#autopilot-rewards). ## Read current verification in the dashboard Open a machine's verification panel to inspect the coordinator's separate App Attest and legacy decisions, verification times and authorization deadlines. Green requires a current server verdict; expired, revoked, unsupported, offline and stale/missing states do not manufacture a current grant from saved hardware trust. App Attest-only machines retain their legacy `self_signed` field. A provider advertising an App Attest protocol other than version 3 displays `unsupported`, even if its reported OS supports App Attest. The footer counts the union once and reports both method counts and overlap. Offline machine records stay in the owned-machine denominator but not current authorization. Public proof views omit raw certificates, receipt blobs and credential identifiers. See [consumer verification](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/consumer/verification.md) and the [wire contract](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/reference/api-contracts.md#verification-presentation-contract). ## App Attest without Darkbloom MDM A failed initial enrollment can leave an Apple key unusable even when its identifier is still in Keychain. Darkbloom replaces that identifier after non-service-unavailable failures or interrupted attempts, subject to the persisted one-hour replacement cooldown and shared hourly generation budget. Service-unavailable failures keep the same key, and already saved enrollment proofs are retained for retry. Do not delete account, machine, Keychain or employer-management state to force retries. This recovery is not proof that the Mac is authorized; check the coordinator verdict before removing Darkbloom MDM. See the [key lifecycle](../reference/app-attest-shadow.md#bounds-and-credential-lifecycle). After a macOS upgrade, the running signed app checks App Attest again on its next coordinator connection. If a completed Apple callback reports key-generation failure without a usable ID, Darkbloom can retry after one minute within its persisted hourly budget; timeout, cancellation and busy admission retain the safer one-hour cooldown. A definite Apple service-unavailable assertion gets one local retry using the same key and challenge. These attempts cannot grant access without Apple's verified proof and the coordinator's applicable authorization, build and security checks. App Attest renewal and transient retries follow a coordinator-driven bounded schedule. The [updated platform recovery policy](https://github.com/Layr-Labs/darkbloom-platform/blob/20b821646acfbf0968d1c30239cb583eeb0fa2bc/docs/reference/provider-authorization.md#controls) distinguishes first-proof backoff from recovery after an accepted proof; retries neither grant permission nor extend the original 15-minute assertion validity, and current policy can shorten serving further. Keep the provider running and check `darkbloom status` or `darkbloom doctor`; persistent native errors still need diagnosis, not credential/profile deletion. This source reference does not establish which schedule a deployed coordinator runs. The [earlier recovery policy](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/reference/provider-authorization.md#controls) is historical evidence, not the current retry schedule. When the coordinator asks the provider to enroll a key that this Mac already enrolled, the provider clears that key and answers `key_unregistered`; the next exchange generates a replacement within the one-hour cooldown and shared hourly generation budget. The replacement goes through the full enrollment checks. Do not delete the Keychain item yourself. `darkbloom doctor` shows the provider's local App Attest state in the `APP ATTEST` section: whether a key is stored and enrolled, any remaining local key-generation safeguard, whether the provider runs in the logged-in GUI session, and a stalled Apple call. The countdown is calculated by the provider; it is not an Apple-supplied deadline or the coordinator's retry time. The coordinator may retry later under its [configured recovery schedule](https://github.com/Layr-Labs/darkbloom-platform/blob/20b821646acfbf0968d1c30239cb583eeb0fa2bc/docs/reference/provider-authorization.md#controls), independently of this local safeguard. The daemon records local state on each coordinator App Attest exchange (`provider-swift/Sources/ProviderCore/Diagnostics/AppAttestLocalDiagnosis.swift`). If Apple reports App Attest as unsupported (`is_supported_false`), log in at the console and run `darkbloom restart` so the provider runs inside the GUI session, and confirm SIP is enabled and Startup Security Utility is set to Full Security. Local key/history observations refresh after every proof exchange, including repeated assertions without another `prepare`. `doctor` and `report` advance displayed ages between exchanges while retaining the original observation metadata. Each `ready` reply carries bounded diagnostics about process start and previous exit, console-user presence, SIP/authenticated root, signing preflight, key history and APNs push history. Failed attestation/assertion replies can additionally carry the native NSError chain. These optional fields are outside the signed transcript and never used for authorization. [`app-attest-shadow.md`](../reference/app-attest-shadow.md) defines them. `darkbloom doctor` explains the available observations with targeted advice ([doctor checks](./troubleshooting.md#doctor-checks)): - `gui session`: a user is logged in, but the provider runs outside that session. Run `darkbloom restart` from the desktop session. - `boot security` / `app signing`: Apple needs Full Security and an intact signed install. Known-invalid checks call for repair in Recovery or reinstallation. Missing signing data or unknown profile expiry produces an indeterminate warning, not a pass. - `key history` / `last apple failure`: generation-attempt totals and the last recorded native failure, or a CryptoTokenKit `-3` key loss after a restart. A generation count plus a recorded `invalidKey` does not establish earlier per-key attestation outcomes. The recorded failure can predate a later success (`provider-swift/Sources/ProviderCore/Diagnostics/AppAttestDeepDiagnosis.swift`, `keyHistory`; `provider-swift/Sources/ProviderAppAttest/AppAttestShadowClient.swift`, `recordAppleFailure`). For the last two, run `darkbloom report` from an administrator account; macOS lets only administrator accounts read the system log. Use `sudo darkbloom report` instead if this account is allowed to use sudo. The report adds device-wide `devicecheckd` observations reduced to closed failure patterns and numeric codes. They can originate from other apps and are not attributable to Darkbloom, so they do not independently diagnose this provider's key. System-log evidence is never collected or sent automatically. On the default in-process path, an Apple DeviceCheck call that never answers keeps later App Attest calls `busy` until the callback arrives or the provider restarts. The provider reports the stall and restarts through the normal drain when idle; see the [thresholds and limits](../reference/app-attest-shadow.md#bounds-and-credential-lifecycle). The log line starts with `App Attest: Apple operation stalled`. An explicit `darkbloom restart` uses the same graceful lifecycle; it is not instant or proof that Apple will accept the next call. The separate [supervised worker candidate](../architecture/security/identity-binding.md#supervised-app-attest-worker-candidate) is internal, defaults off and is **not ready for production**. It retires the worker rather than restarting the inference process; do not enable its [qualification flag](../reference/configuration.md#app-attest-worker-qualification) as an operator workaround. The [recorded native passes](../../scripts/nativequalification/README.md#qualification-status) separate worker components, loaded-engine callback recovery and Stage C resumption. They apply only to the tested signed artifacts; rebuilt binaries need fresh qualification, and physical OS/update/reboot and fleet-rollout gates remain separate. macOS 27, GUI-session checks and an intact signature alone are not Apple acceptance. During a same-process reconnect the provider can answer a fresh, encrypted [endpoint-resumption challenge](../reference/protocol-messages.md#app-attest-endpoint-resumption-candidate) without another Apple call. This proves custody of the existing in-memory key, not local permission to serve or a fresh Apple proof. The coordinator must support the separate protocol and authorize the new connection. Neither resume nor worker replacement extends the coordinator-driven renewal schedule or fifteen-minute proof-validity window; process restart creates a new endpoint key. The matching platform support must recheck retained evidence and current policy. The [isolated native qualification](../reports/2026-10-11-native-serving-resumption-qualification.md) passed with real Apple verification and encrypted inference across a 125-second break on one exact signed candidate. It does not enable production resumption or establish cross-process or worker-recovery continuity. After enrollment, a missing or unverified recurring risk receipt or missing risk metric remains unknown. Under the [updated platform receipt policy](https://github.com/Layr-Labs/darkbloom-platform/blob/20b821646acfbf0968d1c30239cb583eeb0fa2bc/docs/reference/provider-authorization.md#receipt-monitoring-and-stricter-readiness), this alone does not clear an accepted, otherwise valid basic serving grant or require extra assertions. First authorization still requires a fresh cryptographically verified proof and coordinator acceptance under current build, revocation and identity checks. Rewards and MDM-removal readiness retain stricter verified-receipt and decision-freshness requirements; use the coordinator's explicit readiness verdict, not basic serving approval, and do not assume every deployment uses the updated policy. A verified assertion is one step toward authorization. Current serving also requires the complete proof archive, the same authenticated account and machine identity on this connection, a registered official signed build and the current runtime checks. A transient identity or storage refusal remains pending; the coordinator requests another fresh assertion on its bounded retry schedule. Keep the provider running and inspect the current authorization reported by `darkbloom status` or `darkbloom doctor`. A historical `eligible` observation cannot authorize serving or MDM removal by itself. The verified Apple code measurement must match the registered official signed build; registration alone cannot supply missing evidence or repair a mismatch. Do not delete a working credential to bypass that check. New setup on macOS 27 or later skips MDM profile download in both the installer and `darkbloom enroll`. Darkbloom MDM will be deactivated soon; upgrade to macOS 27 to avoid legacy enrollment. A qualified macOS 27 provider can use [App Attest authorization](https://github.com/Layr-Labs/darkbloom-platform/blob/master/docs/reference/provider-authorization.md) when the coordinator explicitly enables it. Start the signed provider and check `darkbloom status` / `darkbloom doctor` for current App Attest authorization. Company-managed Macs keep their employer profile; they do not enroll into Darkbloom MDM for this path. After the coordinator enables removal and reports readiness, run `darkbloom unenroll` and choose the App Attest option. Removal guidance requires a coordinator decision received within the last 10 seconds, as well as a current daemon snapshot and unexpired authorization; a local state-file rewrite cannot extend readiness. It requires macOS 27 or later; `--keep-serving` remains a direct shortcut. The command preserves credentials/account data, validates the exact Darkbloom enrollment and guides removal in System Settings. If the read-only administrator inventory is needed, run the command in the foreground of an interactive terminal: `sudo` reads the password with terminal echo disabled. Refusing authentication, running without a terminal, or running as a background job withholds guidance; no profile is removed by the CLI. The full-exit option stops the provider and offers identity cleanup, so choose App Attest to retain provider identity. New setup remains pending if App Attest is unavailable or unqualified; diagnose with `darkbloom doctor` instead of installing an MDM profile. Under the upcoming policy, the legacy steps below apply only to frozen identities, not to every older-macOS machine or existing local enrollment. `darkbloom logout` stops the provider before removing its saved credential and attempts token revocation. If remote revocation is unconfirmed, its output says so; local deletion is not proof that remote copies were invalidated. See [logout flags and failure behavior](cli-reference.md#darkbloom-login--darkbloom-logout). ## Existing machines and upgrade notices Under the upcoming [frozen legacy policy](../architecture/security/enrollment.md#frozen-legacy-authorization-cohort), only already successfully MDM-verified devices whose stored account, SE key and serial enter the durable cohort continue through legacy verification. The first upgraded production coordinator startup drains eligible historical inventory after revocation replay before freezing. Soft-deleted accounts and provider records cannot qualify for that initial snapshot; see the [cohort qualification rules](../architecture/security/enrollment.md#frozen-legacy-authorization-cohort). A restart, a new account, a new device or a new account association does not reopen eligibility. Reenrollment requires the existing key under its frozen account and the [authenticated signed enrollment request](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/reference/api-contracts.md#legacy-mdm-enrollment-proof). Preserve your key and account; a replacement identity must use qualified App Attest, with no unsupported-OS fallback. Lost or hashless historical evidence may conservatively omit a device; a previous local profile alone does not establish eligibility. Current verification still requires the validated account, same frozen SE key and prior successful MDM evidence. See the [historical evidence and backfill limits](../architecture/security/enrollment.md#frozen-legacy-authorization-cohort); recent/open sessions or incomplete history are not guaranteed to be recovered. `darkbloom enroll` checks the authenticated signed request with the coordinator even when a Darkbloom profile is already installed. Only a successful eligibility check returns "Already enrolled", without saving or reinstalling a profile; this is not a fresh serving grant. No grace period has been chosen and no expiry is implemented. Grandfathered legacy MDM-only serving does not qualify your Mac for base rewards. Base rewards require macOS 27 or later and current qualified App Attest authorization for every provider, old or new, including when the Mac also retains MDM evidence. The OS claim must be bound to that same authorization; missing, malformed or older versions do not qualify. Existing economics guards still apply. Inference/work earnings are unchanged, with no retroactive clawback of rewards. See [billing](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/consumer/billing.md) for the reward policy. Upgrading macOS does not uninstall MDM. After upgrading to macOS 27 and updating the provider, restart it and check `darkbloom status`; remove only the Darkbloom profile through the approved `darkbloom unenroll` App Attest path. Keep employer management installed. Every command in the updated CLI warns on stderr when the local OS is below 27. The setup page and dashboard also show the transition notice; machine warnings use current/last reported OS versions, with missing reports labelled unknown. The notice does not enact a retirement deadline; the cohort restriction is a separate coordinator gate. Older installed binaries receive the CLI notice only after updating. ## Prerequisites - A supported Apple silicon Mac with SIP on and Secure Boot at **Full Security**, running the provider ([`installation.md`](./installation.md), [`hardware-requirements.md`](./hardware-requirements.md)). Both settings are changed only in Recovery; the coordinator checks them independently of your self-report ([Layer 3](../architecture/security/attestation.md#layer-3--mdm-securityinfo-the-hardware-grant)). - For the legacy path below, the Mac must not be enrolled in another MDM. `darkbloom enroll` refuses (`managedByOtherMDM`) and `darkbloom doctor` reports "enrolled in another MDM … hardware trust unavailable on this Mac" ([`../architecture/security/enrollment.md#failure-modes`](../architecture/security/enrollment.md#failure-modes)). - Under the upcoming policy, the legacy steps below are for a frozen identity only, not new onboarding on older macOS. Use the linked provider account and existing SE key; new identities need qualified App Attest. - A real console user logged in (Aqua session), automatic login enabled, auto-logout on idle disabled, and sleep prevented. APNs registration, which the code-identity flag depends on, only works inside a logged-in GUI session; `darkbloom doctor` reports these as `console session`, `automatic login`, `auto-logout on idle` and `sleep prevention` ([`troubleshooting.md#doctor-checks`](./troubleshooting.md#doctor-checks)). - A healthy `darkbloom start`. Registration with a valid Secure-Enclave-signed blob grants `self_signed` at once ([Layer 1](../architecture/security/attestation.md#layer-1--secure-enclave-registration-blob)); `hardware` is only ever granted on top of that. ## Steps ### 1. Enrol the Mac ```bash darkbloom enroll ``` For a frozen identity, the command downloads the enrolment profile from `POST /v1/enroll` using linked provider credentials and a fresh SE-key proof, saves it as `Darkbloom-Enroll-.mobileconfig`, registers it with System Settings and opens the Profiles pane (`EnrollCommand.swift`; options in [`cli-reference.md`](./cli-reference.md#darkbloom-enroll--darkbloom-unenroll)). "Already enrolled" means the Darkbloom profile is present and you can skip to step 3. What the profile contains and the read-only `AccessRights` it requests are in [`../architecture/security/enrollment.md#the-profile`](../architecture/security/enrollment.md#the-profile). ### 2. Approve the profile In **System Settings → General → Device Management**, select *Darkbloom Provider Enrollment*, click **Install**, and authenticate. `mdmclient` then performs SCEP and the MDM check-in against the coordinator's MicroMDM ([operator flow](../architecture/security/enrollment.md#operator-flow)). If the profile is shown as unverified, the coordinator served it unsigned; installing it is still safe because signing is install-time UX only ([profile signing](../architecture/security/enrollment.md#profile-signing)). ### 3. Confirm your posture The coordinator grants `hardware` when Apple's MDM subsystem on your Mac reports SIP enabled and `SecureBootLevel` `full`, in agreement with your attestation blob. Check both before waiting on the coordinator: ```bash csrutil status # System Integrity Protection status: enabled. csrutil authenticated-root status ``` For Secure Boot, open **Startup Security Utility** in Recovery and confirm **Full Security**. Fixing either setting requires a reboot into Recovery, which also restarts the provider. ### 4. Wait for the verification, or re-check Nothing more is needed from you: the coordinator's verification scheduler picks up the enrolled device, sends a `SecurityInfo` command, and grants on the first report that agrees with your blob. A transient outcome (device not found yet, not enrolled, report timed out) leaves your level unchanged and is retried on the scheduler's backoff; only a received report that **contradicts** your blob demotes you ([Layer 3](../architecture/security/attestation.md#layer-3--mdm-securityinfo-the-hardware-grant), [failure modes](../architecture/security/attestation.md#failure-modes)). To re-check after fixing something, restart the provider so it re-registers: ```bash darkbloom restart darkbloom status ``` ### Keeping the level - **Stay online and awake.** Trust is per connection: a reconnect caps a stored `hardware` back to `self_signed`, and the coordinator restores it from durable device evidence on your first passing challenge only within the trust-reuse bounds; otherwise a fresh `SecurityInfo` round-trip runs (trust reuse in [Layer 3](../architecture/security/attestation.md#layer-3--mdm-securityinfo-the-hardware-grant)). Missing the periodic challenge deroutes you; the cadence, timeouts and strike counts are in [Layer 2](../architecture/security/attestation.md#layer-2--periodic-challenge). - **Keep the console session.** `code_attested` is earned through an APNs push that only a logged-in Aqua session can receive; once the operator enables enforcement, un-attested providers receive no private text ([Flag — APNs code identity](../architecture/security/attestation.md#flag--apns-code-identity)). - **Short coordinator reconnects.** A continuously code-verified process can resume through a fresh encrypted WebSocket challenge within the bounded [code-continuity window](../architecture/security/attestation.md#flag--apns-code-identity). Restarting the provider changes its process key; hardware continuity alone does not substitute for code identity. - **Keep the same identity.** The Secure Enclave signing key is persistent in the keychain, so your SE public key survives restarts and is the identity the trust-reuse and code-identity caches are keyed on ([`../architecture/security/identity-binding.md`](../architecture/security/identity-binding.md)). If the keychain path fails — for example a binary without the `keychain-access-groups` entitlement — `ProviderLoop.swift` falls back to an ephemeral key with a warning, you appear as a brand-new identity, and you cannot rejoin the frozen legacy cohort; use qualified App Attest instead. - **Run a released build.** Binary, metallib and model-hash drift against registration untrusts you; `darkbloom update` returns you to a build in the release record ([`cli-reference.md`](./cli-reference.md#darkbloom-update)). ## Verify `darkbloom status` prints the last `trust_status` the coordinator sent as `Trust: / ` (`StatusCommand.swift`). What you want to see: | `Trust:` line | Meaning | |---|---| | `hardware / online` with reason `MDM verification passed` or `MDM verification passed (late SecurityInfo)` | A fresh `SecurityInfo` grant on this connection | | `hardware / online` with a trust-reuse reason (`same_binary`, `continuity`, `approved_release_transition`, `continuity_release_transition`) | Restored from durable device evidence after a reconnect | | `self_signed / online`, reason `SE attestation verified, awaiting MDM verification` | Enrolment not complete or the report has not arrived yet — see Troubleshooting | | any level `/ untrusted` with a failure reason | The coordinator stopped routing to you — see Troubleshooting | The reason strings are listed in [trust status messages](../architecture/security/attestation.md#trust-status-messages-to-providers). `darkbloom doctor` shows the local side: MDM enrolment, SIP, the console-session checks above, and (with `--support`) the coordinator URL and MDM state ([`troubleshooting.md#doctor-checks`](./troubleshooting.md#doctor-checks)). Anyone can read your public verdict — `trust_level`, `mdm_verified`, `mda_verified` and the verified posture fields, never your serial, UDID, APNs token or `code_attested` — from `GET /v1/providers/attestation`; the fields are explained in [../consumer/verification.md#public-attestation-endpoint](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/consumer/verification.md#public-attestation-endpoint). What `hardware` does not prove: it says nothing about *which* binary holds your key (that is `code_attested`) or *which* Apple device (that is `mda_verified`; Apple issues a fresh attestation only about once per device per week, so the flag can lag the level — [Flag — Apple Managed Device Attestation](../architecture/security/attestation.md#flag--apple-managed-device-attestation)). Neither flag changes the level. Single-node inference is the supported security boundary: multi-node RDMA over Thunderbolt bypasses the in-process memory protections and is not trusted. The process defences behind the privacy capabilities the routing gate requires, and their known limits, are recorded in [`../threat-model.yaml`](../threat-model.yaml) and summarised in [`../architecture/components/provider.md#process-boundaries`](../architecture/components/provider.md#process-boundaries); what the provider can and cannot see is in [`../architecture/security/encryption.md#what-each-party-can-observe`](../architecture/security/encryption.md#what-each-party-can-observe). ## Troubleshooting The provider's `status_signature` must cover the same canonical bytes the coordinator reconstructs. `StatusCanonical.build` in `provider-swift/Sources/ProviderCore/Security/AttestationBuilder.swift` matches the coordinator's ordering of mixed-case `model_hashes` and `template_hashes` keys and its escaping of U+2028/U+2029. This encoding correction leaves enrolment, signature verification and trust requirements unchanged; the byte format and failure policy are in [Layer 2](../architecture/security/attestation.md#layer-2--periodic-challenge). | Symptom | Likely cause | Fix | |---|---|---| | `trust_level: self_signed` persists | MDM verification not completed, or identity excluded from frozen cohort | For a frozen identity, reenroll with linked credentials and signed proof; for a new identity, use qualified App Attest and inspect its separate coordinator verdict | | `mdm_verified: false` | Not enrolled, or `SecurityInfo` timed out | Confirm enrolment; wait for the next retry on the [scheduler backoff](../architecture/security/attestation.md#layer-3--mdm-securityinfo-the-hardware-grant) | | `mda_verified: false` while `hardware` | Apple has not issued a fresh attestation yet or the chain did not bind your SE key | Wait; informational only, routing is unaffected | | `trust_status` reason `posture-mismatch` / status `untrusted` | MDM says SIP or Secure Boot differs from your blob | Fix the posture in Recovery (`csrutil enable`, Full Security), reboot, restart the provider | | `code_attested` never passes | No Aqua session / no APNs token / pushes throttled | Log in at the console, enable automatic login, disable auto-logout; check `darkbloom doctor`; a reconnect soon after a proof uses the resume path instead of a push ([Flag — APNs code identity](../architecture/security/attestation.md#flag--apns-code-identity)) | | Derouted after missed challenges | Sleep or network blip | Recovers on the next passing challenge; prevent sleep | | `status signature verification failed` while the plain challenge signature passes | Invalid status signature or a mismatch between provider and coordinator canonical bytes | Run `darkbloom update` and `darkbloom restart`; if it persists, use the diagnostics below. The coordinator continues to reject mismatching signatures | | Binary hash drift warning | Running a build not in the coordinator's release record | `darkbloom update` | | `darkbloom enroll` says the Mac is managed by another MDM | Another MDM profile is installed | Remove it (System Settings → General → Device Management) or use another Mac; `hardware` is unavailable while it is present | | Every flag lost after an update or reinstall | The Secure Enclave key fell back to ephemeral (warning in `darkbloom logs`) | Reinstall a signed release build so the `keychain-access-groups` entitlement is present | For local diagnostics use `darkbloom doctor` and `darkbloom logs --last 1h`. Provider logs are never uploaded automatically; `darkbloom report` uploads a unified-log excerpt to `POST /v1/provider/log-report` only when you run it (`--dry-run` prints it first; [`cli-reference.md`](./cli-reference.md#darkbloom-report)). On macOS 27 the report also carries the App Attest snapshot and the APNs push history. Run from an administrator account (or with `sudo` where allowed), it also carries closed, device-wide `devicecheckd` pattern matches, not provider-specific proof. ## Related - [`../architecture/security/attestation.md`](../architecture/security/attestation.md) — trust levels, the three layers, both flags, the routing gate, invariants, and code map. - [`../architecture/security/enrollment.md`](../architecture/security/enrollment.md) — the MDM profile, operator flow, and webhook. - [`../architecture/security/identity-binding.md`](../architecture/security/identity-binding.md) — how the SE key, `K`, the APNs token, and your account are bound. - [`../architecture/security/encryption.md`](../architecture/security/encryption.md) — the three NaCl Box hops and the privacy statement. - [../consumer/verification.md](https://github.com/Layr-Labs/darkbloom-platform/blob/48a198c71a2d30feec5597bacf1101120f7f955d/docs/consumer/verification.md) — how consumers read your verdict. - [`troubleshooting.md`](./troubleshooting.md) — doctor checks and symptom → fix rows. - [`../design/apns-code-attestation.md`](../design/apns-code-attestation.md) — design record for code identity. Local [cache-volume checks](../architecture/security/encryption.md#provider-cache-storage) are storage suitability checks, not evidence of peripheral firmware authenticity and not part of the coordinator's provider attestation verdict.