diff --git a/apps/node-agent/packaging/build_deb.py b/apps/node-agent/packaging/build_deb.py
index f20be49..92f05de 100644
--- a/apps/node-agent/packaging/build_deb.py
+++ b/apps/node-agent/packaging/build_deb.py
@@ -11,7 +11,7 @@ import sys
ROOT = Path(__file__).resolve().parents[1]
-VERSION = "0.8.5"
+VERSION = "0.8.6"
sys.path.insert(0, str(ROOT.parents[1] / "scripts/packaging"))
from debian import package
diff --git a/docs/audits/2026-09-07-k1-causal-diagnostics-r8.md b/docs/audits/2026-09-07-k1-causal-diagnostics-r8.md
new file mode 100644
index 0000000..bb749ef
--- /dev/null
+++ b/docs/audits/2026-09-07-k1-causal-diagnostics-r8.md
@@ -0,0 +1,44 @@
+# Onboard K1 causal diagnostics R8
+
+The owner screenshot after R7 corresponds to a new network.provision operation,
+not connection.verify. The operation failed at connect-failed in approximately
+68 ms with BleakError, side_effect_status=none and network_not_applied. It did
+not cross the Wi-Fi dispatch boundary. The service remained active without a
+restart. This is distinct from the Linux route-probe TypeError corrected in R7.
+The Bluetooth failure origin remains unproven; a missing BlueZ device object
+is only a hypothesis and is not grounds for an automatic rescan or write retry.
+
+The existing journal logger only recorded PluginExecutionError and the facade
+wrapper stack. The facade retains the native exception as __cause__, but the
+logger did not follow it. The new bounded causal logger records exception class
+and basename/function/line for up to six causes and ten frames per cause. It
+respects suppressed context and terminates cycles. It never renders exception
+messages, source lines, frame locals or payloads. Both journalled and outer
+HTTP failure paths use it. Error responses and device admission are unchanged.
+
+A regression now passes through the actual NodeBridge and plugin facade with
+only the service endpoint replaced. It verifies that the native BleakError
+location survives the real PluginExecutionError wrapper, exactly one connect
+is followed by state observation, and generated secret material is absent from
+logs and the response. A second test covers cyclic and suppressed chains.
+The earlier test substituted NodeBridge.invoke and therefore never exercised
+the wrapper that obscured the installed failure.
+
+The existing wireless modal also distinguishes its two actions more clearly.
+Check K1 state appears before the network fields; the provisioning action is
+now labelled Apply Wi-Fi and check. No new controls, permissions, retries,
+state machine, profiles or host-network changes are introduced. Final Connect
+continues to require current device/session proof.
+
+Validation: 20 NodeBridge/package lifecycle tests, 23 focused frontend and
+architecture checks, 794 full Core frontend tests, Core TypeScript/production
+build and scoped Ruff passed. Node 0.8.6 and optional K1 0.1.5 are reserved for
+this source. Package, installation and owner UI results will be recorded after
+they are observed. This increment improves diagnosis and action clarity; it
+does not claim to fix the physical Bluetooth failure.
+
+The owner screenshot and exact operation result are preserved with UTC and
+monotonic collection timestamps and SHA-256 hashes under private/acceptance/
+k1-node085-20260907-bluetooth-1355. Browser cache clearing for that attempt has
+not been confirmed. No hardware commands were issued by the agent. The next
+physical check remains through the owner UI after clearing browser cache.
diff --git a/plugins/xgrids-k1/frontend/src/sensors/DeviceEnrollmentWindow.tsx b/plugins/xgrids-k1/frontend/src/sensors/DeviceEnrollmentWindow.tsx
index e5eb9ef..36165a7 100644
--- a/plugins/xgrids-k1/frontend/src/sensors/DeviceEnrollmentWindow.tsx
+++ b/plugins/xgrids-k1/frontend/src/sensors/DeviceEnrollmentWindow.tsx
@@ -133,10 +133,14 @@ export function DeviceEnrollmentWindow({transport,onChange,onClose,renderWindow}
{bluetoothFailure&&