Корректное ожидание подтверждения Bridge

This commit is contained in:
DCCONSTRUCTIONS
2026-08-23 12:14:56 +03:00
parent 7d911b4b1f
commit 456141a3f3
4 changed files with 133 additions and 12 deletions
@@ -67,6 +67,7 @@ let reconfigurationAllowsFreshDevice;
let readOnlyObservationShowsNetworkUnavailable;
let readOnlyFailureShowsNetworkUnavailable;
let savedBridgeRequiresNetworkSetup;
let isConnectionControlBootstrapSettling;
let provisioningFailureRequiresFreshCandidate;
let trustedConnectionBinding;
let transportRefEquivalenceKey;
@@ -189,6 +190,7 @@ before(async () => {
readOnlyObservationShowsNetworkUnavailable,
readOnlyFailureShowsNetworkUnavailable,
savedBridgeRequiresNetworkSetup,
isConnectionControlBootstrapSettling,
provisioningFailureRequiresFreshCandidate,
trustedConnectionBinding,
transportRefEquivalenceKey,
@@ -6228,6 +6230,92 @@ test("Apply presentation stays correlated through ACK, bootstrap, terminal and c
);
});
test("current Bridge bootstrap stays visible over an older unresolved STOP checkpoint", () => {
const presentation = provisioningAttemptPresentation({
localPhase: "settling",
attemptId: "network-operation-current",
});
const state = durableTopologyState();
state.snapshot_runtime_id = presentation.snapshotRuntimeId;
state.connection_attempt = {
schema_version: "missioncore.xgrids-k1-connection-attempt/v1",
attempt_id: presentation.attemptId,
connection_mode: "bridge",
status: "running",
phase: "network_applied",
control_state: "unknown",
stage: "mqtt-device-info",
public_error_code: null,
side_effect_status: "applied",
safe_next_action: "wait-for-current-attempt",
automatic_retry: false,
accepted_at: OBSERVED_AT,
completed_at: null,
timeline: [],
};
state.operations = [{
operation_id: presentation.attemptId,
action: "network.provision",
status: "succeeded",
idempotency_key: presentation.idempotencyKey,
}];
state.physical_command = {
status: "unresolved",
reason_code: "physical-command-reconciliation-required",
requires_reconciliation: true,
resolved_active_recovery_required: false,
automatic_replay_allowed: false,
runtime_bound: true,
reconciliation_ready: true,
observed_session_state: "scan_stopping",
active_operation_id: "older-stop-operation",
record: {
revision: 306,
operation_id: "older-stop-operation",
action: "stop",
stage: "observing",
resolution: null,
connection: {
transport_ref: presentation.deviceId,
connection_mode: "quick-connect",
target_ipv4: "192.168.56.1",
},
},
};
assert.equal(isConnectionControlBootstrapSettling(state), true);
const markup = renderProvisioningWithAttempt({
controller: provisioningController(state),
desiredMode: "bridge",
}, presentation);
assert.match(markup, /Подтверждение подключения…/);
assert.match(markup, /Настройки переданы один раз/);
assert.match(markup, /<span>02<\/span>/);
assert.match(markup, /nodedc-activity-indicator/);
assert.doesNotMatch(markup, /Прежнее подключение не подтверждено/);
assert.doesNotMatch(markup, />Переподключиться<\/button>/);
assert.doesNotMatch(markup, />Подключить новый K1<\/button>/);
assert.equal(isConnectionControlBootstrapSettling({
...state,
connection_attempt: {
...state.connection_attempt,
status: "succeeded",
safe_next_action: "verify-control-read-only",
},
}), true);
assert.equal(isConnectionControlBootstrapSettling({
...state,
connection_attempt: {
...state.connection_attempt,
status: "failed",
control_state: "control_not_ready",
safe_next_action: "manual-recovery-required",
},
}), false);
});
test("Apply spends secret state before I/O and never stores a password in its presentation latch", () => {
const source = readFileSync(provisioningSourceUrl, "utf8");
const presentationType = sourceSlice(