chore(k1): checkpoint connection recovery work

This commit is contained in:
DCCONSTRUCTIONS
2026-08-21 08:12:22 +03:00
parent a3138f3d71
commit c7843a3c7e
22 changed files with 969 additions and 293 deletions
+34 -16
View File
@@ -812,6 +812,26 @@ export function readOnlyFailureShowsNetworkUnavailable(
&& READ_ONLY_NETWORK_UNAVAILABLE_REASON_CODES.has(reasonCode);
}
/**
* Preserve the stronger BLE observation across refreshes and later scan
* failures: this saved Bridge needs network setup, not another old-address
* reconnect attempt.
*/
export function savedBridgeRequiresNetworkSetup(
state: XgridsK1State | null | undefined,
): boolean {
if (
state?.connection_verification?.reason_code
=== "connection-verify-address-unavailable"
) return true;
const operation = state?.last_operation;
return Boolean(
operation?.action === "connection.verify"
&& operation.status === "failed"
&& operation.error?.code === "connection-verify-address-unavailable",
);
}
export function requiresReadOnlyPhysicalRecovery(
state: XgridsK1State | null | undefined,
): boolean {
@@ -1201,24 +1221,15 @@ ReadonlyArray<ReadOnlyNetworkObservationAction> = [
/**
* Resolve a recovery Verify target from the public policy, never from a
* browser selection. The backend recommendation wins when it names an exact
* allowed observation; older compatible projections fall back in the same
* current -> configured -> fresh order used by the supervisor.
* browser selection. A reconnect must prefer already bound or durable state
* over a projected fresh scan: a browser projection cannot prove that the
* native BLEDevice is still retained by the backend process. The backend
* policy still decides which exact actions are allowed; this helper only
* chooses the safest allowed source in current -> configured -> fresh order.
*/
export function recommendedConnectionRecoveryObservationTarget(
state: XgridsK1State | null | undefined,
): ReadOnlyConnectionObservationTarget | null {
const recommended = state?.connection_policy?.recommended_action;
const orderedActions = SERVER_BOUND_RECOVERY_OBSERVATION_PRIORITY.includes(
recommended as ReadOnlyNetworkObservationAction,
)
? [
recommended as ReadOnlyNetworkObservationAction,
...SERVER_BOUND_RECOVERY_OBSERVATION_PRIORITY.filter(
(action) => action !== recommended,
),
]
: SERVER_BOUND_RECOVERY_OBSERVATION_PRIORITY;
const sources: Record<
ReadOnlyNetworkObservationAction,
ReadOnlyConnectionObservationSource
@@ -1227,7 +1238,7 @@ export function recommendedConnectionRecoveryObservationTarget(
"observe-configured-device-network": "durable-configured-state",
"observe-fresh-device-network": "fresh-scan",
};
for (const action of orderedActions) {
for (const action of SERVER_BOUND_RECOVERY_OBSERVATION_PRIORITY) {
const target = exactPolicyObservationTarget(state, action, sources[action]);
if (target?.serverBound) return target;
}
@@ -1282,6 +1293,13 @@ export function readOnlyConnectionObservationTarget(
selectedDeviceId = "",
selectedConnectionMode: XgridsConnectionMode | null = null,
): ReadOnlyConnectionObservationTarget | null {
// An unresolved physical command must first use the exact durable
// DeviceInfo path when the supervisor authorizes it. A projected fresh BLE
// row can outlive the backend's native BLEDevice and therefore cannot
// outrank this read-only reconciliation route.
const exactControl = exactControlVerificationTarget(state);
if (exactControl) return exactControl;
const exactFresh = exactPolicyObservationTarget(
state,
"observe-fresh-device-network",
@@ -1327,7 +1345,7 @@ export function readOnlyConnectionObservationTarget(
state,
"observe-configured-device-network",
"durable-configured-state",
) ?? exactControlVerificationTarget(state);
);
}
/**