feat(k1): add local connection matrix

This commit is contained in:
DCCONSTRUCTIONS
2026-07-19 09:52:22 +03:00
parent fecb5885d0
commit 57b2208cae
20 changed files with 1405 additions and 115 deletions
+4 -3
View File
@@ -65,6 +65,7 @@ export interface XgridsCompatibilityState {
firmware_claim?: string | null;
vendor_writes_enabled?: boolean;
camera_preview?: string | null;
attestation?: CompatibilityAttestation | null;
}
export interface XgridsModelingControlSafety {
@@ -289,7 +290,7 @@ export interface XgridsK1State {
devices?: BleDevice[];
selected_device_id?: string | null;
k1_ip?: string | null;
connection_mode?: "bridge" | null;
connection_mode?: "bridge" | "quick-connect" | "direct-connect" | null;
foxglove_ws_url?: string | null;
foxglove_viewer_url?: string | null;
rerun_grpc_url?: string | null;
@@ -322,7 +323,7 @@ export interface ScanRequest {
export interface CompatibilityAttestation {
firmware_version: "3.0.2";
topology: "direct-lan";
topology: "direct-lan" | "device-ap" | "controller-hotspot";
verification: "live-device-info";
}
@@ -330,7 +331,7 @@ export interface ConnectRequest {
device_id: string;
ssid: string;
password: string;
connection_mode: "bridge";
connection_mode: "bridge" | "quick-connect" | "direct-connect";
compatibility_attestation: CompatibilityAttestation;
operation_id?: string;
idempotency_key?: string;
@@ -1,7 +1,24 @@
import type { CompatibilityAttestation } from "./api";
import type { ConnectionMode } from "./configuration";
export const EXACT_PROFILE_SELECTION: CompatibilityAttestation = Object.freeze({
firmware_version: "3.0.2",
topology: "direct-lan",
verification: "live-device-info",
});
const topologyByConnectionMode = {
bridge: "direct-lan",
"quick-connect": "device-ap",
"direct-connect": "controller-hotspot",
} as const satisfies Record<ConnectionMode, CompatibilityAttestation["topology"]>;
export function profileSelectionForConnectionMode(
connectionMode: ConnectionMode,
): CompatibilityAttestation {
return {
firmware_version: "3.0.2",
topology: topologyByConnectionMode[connectionMode],
verification: "live-device-info",
};
}
@@ -11,7 +11,7 @@ import {
type StatusTone,
} from "@nodedc/ui-react";
import { EXACT_PROFILE_SELECTION } from "../compatibility";
import { profileSelectionForConnectionMode } from "../compatibility";
import {
SUPPORTED_GNSS_MODE,
SUPPORTED_MOUNT_TYPE,
@@ -149,7 +149,9 @@ export function K1AcquisitionPipeline({
project_name: projectNameValidation.value,
mount_type: SUPPORTED_MOUNT_TYPE,
gnss_mode: SUPPORTED_GNSS_MODE,
compatibility_attestation: EXACT_PROFILE_SELECTION,
compatibility_attestation: profileSelectionForConnectionMode(
state.connection_mode ?? "bridge",
),
},
physicalAcceptance: PHYSICAL_ACCEPTANCE,
}),
@@ -11,9 +11,9 @@ import {
} from "@nodedc/ui-react";
import type { BleDevice } from "../api";
import { EXACT_PROFILE_SELECTION } from "../compatibility";
import { profileSelectionForConnectionMode } from "../compatibility";
import {
SUPPORTED_CONNECTION_MODE,
DEFAULT_CONNECTION_MODE,
connectionModeOptions,
type ConnectionMode,
} from "../configuration";
@@ -21,6 +21,36 @@ import { provisioningIntentKey } from "../lifecycle";
import { finiteMetric } from "../presentation";
import type { XgridsK1Controller } from "../runtimeContext";
const connectionCopy: Record<ConnectionMode, {
stepTitle: string;
ssidLabel: string;
ssidPlaceholder: string;
buttonLabel: string;
safetyNote: string;
}> = {
bridge: {
stepTitle: "Передайте настройки общей сети",
ssidLabel: "Название общей сети Wi‑Fi",
ssidPlaceholder: "Сеть локального контура",
buttonLabel: "Подключить K1 к общей сети",
safetyNote: "K1 получит реквизиты существующей сети одним рассмотренным BLE-запросом без автоматического повтора.",
},
"quick-connect": {
stepTitle: "Подключитесь к точке доступа K1",
ssidLabel: "Название точки доступа K1",
ssidPlaceholder: "SSID сканера, например XGR-…",
buttonLabel: "Подключить этот Mac к K1",
safetyNote: "Введите SSID и пароль точки доступа вашего K1. Mac сменит текущую Wi‑Fi сеть одним CoreWLAN-запросом; недокументированный BLE-секрет не читается и K1 не получает BLE-запись.",
},
"direct-connect": {
stepTitle: "Подключите K1 к хотспоту контроллера",
ssidLabel: "Название хотспота контроллера",
ssidPlaceholder: "SSID управляющего устройства",
buttonLabel: "Подключить K1 к хотспоту",
safetyNote: "Хотспот должен быть уже включён, а этот Mac — иметь к нему маршрут. K1 получит его реквизиты одним рассмотренным BLE-запросом.",
},
};
function WizardStep({
number,
title,
@@ -96,13 +126,17 @@ export function K1ProvisioningPipeline({
const [ssid, setSsid] = useState("");
const [password, setPassword] = useState("");
const [connectionMode, setConnectionMode] = useState<ConnectionMode>(
SUPPORTED_CONNECTION_MODE,
DEFAULT_CONNECTION_MODE,
);
const provisioningIntentRef = useRef<string | null>(null);
const devices = state?.devices ?? [];
const isBusy = pendingAction !== null;
const credentialsReady = ssid.trim().length > 0 && password.length > 0;
const canConnect = powerConfirmed && selectedDeviceId.length > 0 && credentialsReady && !isBusy;
const modeCopy = connectionCopy[connectionMode];
const selectedModeConnected = Boolean(
state?.k1_ip && state.connection_mode === connectionMode,
);
useEffect(() => {
if (state?.selected_device_id) {
@@ -117,6 +151,12 @@ export function K1ProvisioningPipeline({
}
}, [selectedDeviceId, state?.devices, state?.selected_device_id]);
useEffect(() => {
if (state?.connection_mode) {
setConnectionMode(state.connection_mode);
}
}, [state?.connection_mode]);
const deviceSummary = useMemo(
() => devices.find((device) => device.device_id === selectedDeviceId),
[devices, selectedDeviceId],
@@ -134,8 +174,8 @@ export function K1ProvisioningPipeline({
device_id: selectedDeviceId,
ssid: ssid.trim(),
password,
connection_mode: SUPPORTED_CONNECTION_MODE,
compatibility_attestation: EXACT_PROFILE_SELECTION,
connection_mode: connectionMode,
compatibility_attestation: profileSelectionForConnectionMode(connectionMode),
idempotency_key: idempotencyKey,
});
if (succeeded) {
@@ -152,7 +192,7 @@ export function K1ProvisioningPipeline({
</header>
<div className="configuration-anchor">
<span className="nodedc-field__description">
Неподтверждённые сетевые топологии уже отражены в интерфейсе, но не могут быть выбраны до отдельной приёмки.
Выберите направление связи. Каждый путь выполняет не более одного сетевого изменения и не повторяет его автоматически.
</span>
<Select
label="Способ подключения"
@@ -160,6 +200,8 @@ export function K1ProvisioningPipeline({
options={connectionModeOptions}
onChange={(value) => {
setConnectionMode(value);
setSsid("");
setPassword("");
resetProvisioningIntent();
}}
disabled={isBusy}
@@ -206,19 +248,19 @@ export function K1ProvisioningPipeline({
</WizardStep>
<WizardStep
number="03"
title="Передайте настройки общей сети"
status={state?.k1_ip ? "Адрес ранее получен" : "Настройки не переданы"}
tone={state?.k1_ip ? "warning" : "neutral"}
title={modeCopy.stepTitle}
status={selectedModeConnected ? "Адрес получен" : "Ожидает подключения"}
tone={selectedModeConnected ? "success" : "neutral"}
>
<div className="field-stack">
<TextField label="Название сети Wi‑Fi" hint="SSID" value={ssid} onChange={(event) => { setSsid(event.target.value); provisioningIntentRef.current = null; }} autoComplete="off" spellCheck={false} placeholder="Сеть локального контура" />
<TextField label={modeCopy.ssidLabel} hint="SSID" value={ssid} onChange={(event) => { setSsid(event.target.value); provisioningIntentRef.current = null; }} autoComplete="off" spellCheck={false} placeholder={modeCopy.ssidPlaceholder} />
<TextField label="Пароль WiFi" hint="Только в оперативной памяти" type="password" value={password} onChange={(event) => { setPassword(event.target.value); provisioningIntentRef.current = null; }} autoComplete="off" placeholder="Введите пароль" />
</div>
<div className="connection-summary"><span>Устройство</span><strong>{deviceSummary?.name || selectedDeviceId || "Сначала выберите устройство"}</strong></div>
<Button width="full" variant="primary" icon={<Icon name="network" />} disabled={!canConnect} onClick={() => void submitConnect()}>
{pendingAction === "connect" ? "Подключаем…" : "Подключить устройство к Wi‑Fi"}
{pendingAction === "connect" ? "Подключаем…" : modeCopy.buttonLabel}
</Button>
<p className="safety-note">Наличие адреса подтверждает результат предыдущей настройки, но не текущее соединение. Пароль передаётся только локальному сервису, не сохраняется в браузере и удаляется из формы после успеха.</p>
<p className="safety-note">{modeCopy.safetyNote} Пароль передаётся только локальному сервису, не сохраняется в браузере и удаляется из формы после успеха.</p>
</WizardStep>
</div>
</GlassSurface>
@@ -4,7 +4,7 @@ export type ConnectionMode = "bridge" | "quick-connect" | "direct-connect";
export type MountType = "handheld" | "vehicle-mounted" | "uav" | "backpack";
export type GnssMode = "none" | "rtk" | "ppk";
export const SUPPORTED_CONNECTION_MODE = "bridge" as const satisfies ConnectionMode;
export const DEFAULT_CONNECTION_MODE = "bridge" as const satisfies ConnectionMode;
export const SUPPORTED_MOUNT_TYPE = "handheld" as const satisfies MountType;
export const SUPPORTED_GNSS_MODE = "none" as const satisfies GnssMode;
@@ -12,19 +12,17 @@ export const connectionModeOptions: Array<SelectOption<ConnectionMode>> = [
{
value: "bridge",
label: "Общая сеть · Bridge",
description: "K1 и Mission Core работают в одной локальной сети. Подтверждённый путь.",
description: "Mission Core передаёт K1 реквизиты существующей общей сети.",
},
{
value: "quick-connect",
label: "Точка доступа K1 · Quick Connect",
description: "Mission Core подключается к сети сканера. Будет доступно после отдельной приёмки.",
disabled: true,
description: "Этот Mac один раз подключается к WiFi сканера; K1 остаётся точкой доступа.",
},
{
value: "direct-connect",
label: "Хотспот контроллера · Direct Connect",
description: "K1 подключается к сети управляющего устройства. Будет доступно после отдельной приёмки.",
disabled: true,
description: "Mission Core передаёт K1 реквизиты хотспота управляющего устройства.",
},
];
@@ -0,0 +1,79 @@
import CoreWLAN
import Foundation
private struct AssociationRequest: Decodable {
let ssid: String
let password: String
}
private struct AssociationResponse: Encodable {
let ok: Bool
let alreadyAssociated: Bool?
let reasonCode: String?
enum CodingKeys: String, CodingKey {
case ok
case alreadyAssociated = "already_associated"
case reasonCode = "reason_code"
}
}
private func emit(_ response: AssociationResponse, exitCode: Int32) -> Never {
let encoder = JSONEncoder()
if let data = try? encoder.encode(response) {
FileHandle.standardOutput.write(data)
}
exit(exitCode)
}
private let input = FileHandle.standardInput.readDataToEndOfFile()
guard input.count <= 1024 else {
emit(
AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "request-too-large"),
exitCode: 1
)
}
do {
let request = try JSONDecoder().decode(AssociationRequest.self, from: input)
guard let ssidData = request.ssid.data(using: .utf8),
(1 ... 32).contains(ssidData.count),
let passwordData = request.password.data(using: .utf8),
(1 ... 64).contains(passwordData.count)
else {
emit(
AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "credential-bounds"),
exitCode: 1
)
}
guard let interface = CWWiFiClient.shared().interface() else {
emit(
AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "wifi-interface-unavailable"),
exitCode: 1
)
}
if interface.ssid() == request.ssid {
emit(AssociationResponse(ok: true, alreadyAssociated: true, reasonCode: nil), exitCode: 0)
}
let networks = try interface.scanForNetworks(withSSID: ssidData)
guard let network = networks.first(where: { $0.ssid == request.ssid }) else {
emit(
AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "network-not-found"),
exitCode: 1
)
}
try interface.associate(to: network, password: request.password)
// CoreWLAN's synchronous association call throws on failure. Reading the
// current SSID again would require Location authorization on recent macOS
// versions and could turn a successful association into a false negative.
emit(AssociationResponse(ok: true, alreadyAssociated: false, reasonCode: nil), exitCode: 0)
} catch {
emit(
AssociationResponse(ok: false, alreadyAssociated: nil, reasonCode: "corewlan-error"),
exitCode: 1
)
}
+6 -4
View File
@@ -3,7 +3,7 @@
"kind": "DevicePlugin",
"metadata": {
"id": "nodedc.device.xgrids-lixelkity-k1",
"version": "0.5.0",
"version": "0.6.0",
"displayName": "XGRIDS K1 Integration"
},
"spec": {
@@ -14,14 +14,15 @@
},
"compatibilityProfiles": [
{
"profileId": "xgrids.lixelkity-k1.fw-3.0.2.direct-lan.v1",
"path": "profiles/fw-3.0.2/direct-lan.v1.json",
"profileId": "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2",
"path": "profiles/fw-3.0.2/local-network.v2.json",
"modelId": "xgrids.lixelkity-k1"
}
],
"permissions": [
"device.discovery.ble",
"device.provisioning.wifi-over-ble",
"host.network.wifi-associate-local",
"network.mqtt.subscribe-private-lan",
"network.mqtt.publish-private-lan",
"network.rtsp.read-private-lan",
@@ -61,11 +62,12 @@
"vendor": "XGRIDS",
"displayName": "XGRIDS LixelKity K1",
"category": "Мобильный лидарный сканер",
"description": "Проверенный локальный профиль: BLE-настройка Wi-Fi, MQTT-приём, облако точек, поза и raw-first запись.",
"description": "Локальный профиль Bridge, Quick Connect и Direct Connect: BLE/CoreWLAN, MQTT, камеры и raw-first запись.",
"verified": true,
"capabilities": [
{ "id": "device.discovery.ble", "label": "Поиск BLE" },
{ "id": "device.provisioning.wifi-over-ble", "label": "Wi-Fi через BLE" },
{ "id": "host.network.wifi-associate-local", "label": "Подключение к точке доступа K1" },
{ "id": "spatial.point-cloud.live", "label": "Облако точек" },
{ "id": "spatial.pose.live", "label": "Траектория" },
{ "id": "device.modeling.live", "label": "Метрики маршрута" },
+61 -12
View File
@@ -12,8 +12,10 @@ from pathlib import Path
from typing import Any
PROFILE_SCHEMA_VERSION = 1
DEFAULT_PROFILE_ID = "xgrids.lixelkity-k1.fw-3.0.2.direct-lan.v1"
DEFAULT_PROFILE_PATH = Path(__file__).parent / "profiles" / "fw-3.0.2" / "direct-lan.v1.json"
DEFAULT_PROFILE_ID = "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2"
DEFAULT_PROFILE_PATH = (
Path(__file__).parent / "profiles" / "fw-3.0.2" / "local-network.v2.json"
)
EVIDENCE_FLAGS = (
"observed",
"decoded",
@@ -129,6 +131,49 @@ def _validate_sources(profile: dict[str, Any]) -> set[str]:
return set(sources)
def _validate_connection_modes(scope: dict[str, Any]) -> None:
modes = _unique_index(
_array(scope.get("connection_modes"), "$.scope.connection_modes"),
"$.scope.connection_modes",
)
expected = {
"bridge": {
"topology": "direct-lan",
"direction": "k1-joins-existing-network",
"device_network_action": "single-reviewed-ble-provisioning-write",
"host_network_action": "none",
"target_address_policy": "ble-status-non-ap-private-ipv4",
"acceptance": "mission-core-physical-accepted",
},
"direct-connect": {
"topology": "controller-hotspot",
"direction": "k1-joins-controller-network",
"device_network_action": "single-reviewed-ble-provisioning-write",
"host_network_action": "operator-prepared-hotspot",
"target_address_policy": "ble-status-non-ap-private-ipv4",
"acceptance": "implementation-ready-physical-acceptance-pending",
},
"quick-connect": {
"topology": "device-ap",
"direction": "controller-joins-k1-network",
"device_network_action": "none",
"host_network_action": "single-corewlan-association",
"target_address_policy": "reviewed-fixed-k1-ap-private-ipv4",
"acceptance": (
"lixelgo-data-plane-observed-mission-core-physical-acceptance-pending"
),
},
}
if set(modes) != set(expected):
raise CompatibilityProfileError("connection mode set differs from reviewed evidence")
for mode_id, expected_fields in expected.items():
actual = {key: value for key, value in modes[mode_id].items() if key != "id"}
if actual != expected_fields:
raise CompatibilityProfileError(
f"connection mode {mode_id!r} differs from reviewed evidence"
)
def _validate_source_references(value: Any, source_ids: set[str], path: str = "$") -> None:
if isinstance(value, dict):
if "source_ids" in value:
@@ -155,7 +200,7 @@ def _validate_transports(profile: dict[str, Any]) -> None:
)
if set(transports) != {
"ble.wifi-bootstrap.fw3.v1",
"mqtt.direct-lan.fw3.v1",
"mqtt.local-ipv4.fw3.v1",
"rtsp.camera-preview.fw3.v1",
}:
raise CompatibilityProfileError("$.transports must contain only the reviewed v1 transports")
@@ -180,14 +225,14 @@ def _validate_transports(profile: dict[str, Any]) -> None:
physical_verified=True,
)
mqtt = transports["mqtt.direct-lan.fw3.v1"]
mqtt = transports["mqtt.local-ipv4.fw3.v1"]
if mqtt.get("protocol") != "MQTT 3.1.1":
raise CompatibilityProfileError("direct-LAN application protocol must remain MQTT 3.1.1")
raise CompatibilityProfileError("local application protocol must remain MQTT 3.1.1")
network = _object(mqtt.get("network"), "$.transports[mqtt].network")
if network.get("transport") != "TCP" or network.get("port") != 1883:
raise CompatibilityProfileError("direct-LAN MQTT endpoint must remain TCP 1883")
raise CompatibilityProfileError("local MQTT endpoint must remain TCP 1883")
if network.get("tls") is not False or network.get("authentication") != "none-observed":
raise CompatibilityProfileError("direct-LAN MQTT security claim differs from observation")
raise CompatibilityProfileError("local MQTT security claim differs from observation")
allowlist = _array(
mqtt.get("subscription_allowlist"),
"$.transports[mqtt].subscription_allowlist",
@@ -202,7 +247,7 @@ def _validate_transports(profile: dict[str, Any]) -> None:
)
_expect_evidence(
mqtt,
"$.transports[mqtt.direct-lan.fw3.v1]",
"$.transports[mqtt.local-ipv4.fw3.v1]",
observed=True,
decoded=False,
replay_verified=False,
@@ -504,7 +549,7 @@ def _validate_acquisition_control(profile: dict[str, Any]) -> None:
def validate_compatibility_profile(profile: Any) -> dict[str, Any]:
"""Validate and return one read-only firmware-3/direct-LAN profile object."""
"""Validate the read-only firmware-3 local connection matrix."""
root = _object(profile, "$")
if root.get("schema_version") != PROFILE_SCHEMA_VERSION:
raise CompatibilityProfileError("unsupported compatibility profile schema_version")
@@ -519,8 +564,9 @@ def validate_compatibility_profile(profile: Any) -> dict[str, Any]:
firmware = _object(scope.get("firmware"), "$.scope.firmware")
if firmware != {"match": "exact", "version": "3.0.2"}:
raise CompatibilityProfileError("profile must match firmware 3.0.2 exactly")
if scope.get("topology") != "direct-lan":
raise CompatibilityProfileError("profile topology must remain direct-lan")
if scope.get("topology") != "local-network-matrix":
raise CompatibilityProfileError("profile topology must remain local-network-matrix")
_validate_connection_modes(scope)
vocabulary = _object(root.get("evidence_vocabulary"), "$.evidence_vocabulary")
if set(vocabulary) != set(EVIDENCE_FLAGS):
@@ -580,7 +626,10 @@ def matches_target(
validated = validate_compatibility_profile(profile)
scope = validated["scope"]
firmware_scope = _object(scope.get("firmware"), "$.scope.firmware")
return firmware_scope.get("version") == firmware and scope.get("topology") == topology
modes = _array(scope.get("connection_modes"), "$.scope.connection_modes")
return firmware_scope.get("version") == firmware and any(
isinstance(mode, dict) and mode.get("topology") == topology for mode in modes
)
def _main() -> int:
@@ -0,0 +1,496 @@
{
"schema_version": 1,
"profile_id": "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2",
"profile_status": "experimental-evidence-backed",
"scope": {
"vendor": "XGRIDS",
"model": "LixelKity K1",
"platform_type": "A4",
"firmware": {
"match": "exact",
"version": "3.0.2"
},
"topology": "local-network-matrix",
"claim_limit": "One owner-controlled K1 on exact firmware 3.0.2 across controlled Bridge/Mission Core and owner-operated Quick Connect LixelGO/iPhone runs. Direct Connect reuses the physically accepted 99-byte BLE Wi-Fi frame but still requires its own Mission Core physical acceptance. This is not a vendor API or a cross-firmware compatibility claim.",
"connection_modes": [
{
"id": "bridge",
"topology": "direct-lan",
"direction": "k1-joins-existing-network",
"device_network_action": "single-reviewed-ble-provisioning-write",
"host_network_action": "none",
"target_address_policy": "ble-status-non-ap-private-ipv4",
"acceptance": "mission-core-physical-accepted"
},
{
"id": "direct-connect",
"topology": "controller-hotspot",
"direction": "k1-joins-controller-network",
"device_network_action": "single-reviewed-ble-provisioning-write",
"host_network_action": "operator-prepared-hotspot",
"target_address_policy": "ble-status-non-ap-private-ipv4",
"acceptance": "implementation-ready-physical-acceptance-pending"
},
{
"id": "quick-connect",
"topology": "device-ap",
"direction": "controller-joins-k1-network",
"device_network_action": "none",
"host_network_action": "single-corewlan-association",
"target_address_policy": "reviewed-fixed-k1-ap-private-ipv4",
"acceptance": "lixelgo-data-plane-observed-mission-core-physical-acceptance-pending"
}
]
},
"evidence_vocabulary": {
"observed": "The channel, transport, or physical behavior was directly seen on the owner-controlled K1.",
"decoded": "A bounded decoder produces the stated semantic payload from observed bytes; transport framing alone is not a semantic decode.",
"replay_verified": "A captured payload of this semantic channel has passed the repository replay-to-view path.",
"physical_verified": "The result was correlated with a controlled physical K1 state or operator action.",
"write_enabled": "This profile authorizes software to emit the state-changing vendor request. False never grants runtime write authority."
},
"safety": {
"default_mode": "read-only",
"vendor_writes_enabled": false,
"unknown_firmware_policy": "reject-profile",
"request_topic_subscription_enabled": false,
"notes": [
"Loading this descriptive profile does not authorize a BLE or MQTT write.",
"The reviewed Wi-Fi provisioning procedure remains a separate explicit operator action and is not activated by loading this profile.",
"Observed LixelGO modeling requests remain write-disabled in this descriptive profile; the separately installed acceptance transport requires a live DeviceInfo match and one operator-present action permit.",
"Unknown firmware, transport, topics, fields, and action responses fail closed."
]
},
"evidence_sources": [
{
"id": "wifi-provisioning-profile",
"kind": "reviewed-profile",
"path": "docs/04_K1_WIFI_PROVISIONING_PROFILE.md",
"scope": "Observed firmware, GATT UUIDs, 99-byte provisioning frame, status read and physical LAN association."
},
{
"id": "mqtt-stream-profile",
"kind": "reviewed-profile",
"path": "docs/05_K1_MQTT_STREAM_PROFILE.md",
"scope": "Local MQTT transport, report topics, bounded point/pose codecs and static modeling-request mapping."
},
{
"id": "lab-001",
"kind": "redacted-physical-lab-report",
"path": "docs/lab/001_K1_LIVE_MQTT_20260715.redacted.md",
"scope": "Physical BLE-to-Wi-Fi result, MQTT message counts, point/pose decode totals and negative camera observation."
},
{
"id": "live-viewer-profile",
"kind": "implemented-path-description",
"path": "docs/06_K1_LIVE_VIEWER.md",
"scope": "Raw-first live/replay path for point cloud and pose."
},
{
"id": "lab-002",
"kind": "redacted-physical-protocol-report",
"path": "docs/lab/002_LIXELGO_IPHONE_LOCAL_PROTOCOL_20260716.redacted.md",
"scope": "Owner-operated LixelGO start/stop mapping, local-only bounded traffic result and left/right RTSP/H.264 camera-preview discovery."
}
],
"transports": [
{
"id": "ble.wifi-bootstrap.fw3.v1",
"role": "bootstrap-and-status",
"protocol": "BLE GATT",
"service_uuid": "00007f00-0000-1000-8000-00805f9b34fb",
"characteristics": {
"wifi_request": "00007f01-0000-1000-8000-00805f9b34fb",
"wifi_status": "00007f02-0000-1000-8000-00805f9b34fb"
},
"reviewed_profile_id": "xgrids-k1-fw3-wifi-v1",
"request_frame_bytes": 99,
"status_semantics": {
"ap_baseline_ipv4": "192.168.56.1",
"lan_acceptance": "A non-AP private IPv4 must be observed and independently confirmed on the intended LAN."
},
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"wifi-provisioning-profile",
"lab-001"
]
},
{
"id": "mqtt.local-ipv4.fw3.v1",
"role": "report-data-plane",
"protocol": "MQTT 3.1.1",
"network": {
"transport": "TCP",
"port": 1883,
"tls": false,
"authentication": "none-observed",
"addressing": "confirmed-device-private-ipv4-only"
},
"subscription_allowlist": [
"lixel/application/report/#",
"RealtimePointcloud",
"RealtimePath",
"DeviceStatus"
],
"evidence": {
"observed": true,
"decoded": false,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001",
"live-viewer-profile",
"lab-002"
]
},
{
"id": "rtsp.camera-preview.fw3.v1",
"role": "camera-preview-data-plane",
"protocol": "RTSP 1.0 with interleaved RTP over TCP",
"network": {
"transport": "TCP",
"port": 8554,
"tls": false,
"authentication": "none-observed",
"addressing": "confirmed-device-private-ipv4-only"
},
"media": {
"codec": "H.264",
"rtp_payload_type": 96,
"clock_hz": 90000,
"framing": "RTP/AVP/TCP interleaved channels 0-1"
},
"evidence": {
"observed": true,
"decoded": false,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"lab-002"
]
}
],
"channels": [
{
"id": "spatial.point-cloud.live",
"kind": "point-cloud",
"direction": "device-report",
"topic": "lixel/application/report/lio_pcl",
"wire_format": "protobuf MqttCompressMsg containing raw-LZ4 LioPclReport",
"semantic_payload": "metric XYZ, complete uint32 rgbi and verified low-byte intensity",
"bounds": {
"max_mqtt_payload_bytes": 2097152,
"max_compressed_bytes": 1048576,
"max_decoded_bytes": 8388608,
"max_expansion_ratio": 64,
"max_points_per_frame": 250000
},
"unverified_fields": [
"upper 24 bits of rgbi as RGB",
"sensor timestamp epoch",
"sensor-to-vehicle extrinsics"
],
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": true,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001",
"live-viewer-profile"
]
},
{
"id": "spatial.pose.live",
"kind": "pose",
"direction": "device-report",
"topic": "lixel/application/report/lio_pose",
"wire_format": "protobuf LioPoseReport",
"semantic_payload": "position XYZ, quaternion XYZW, distance and pose accuracy",
"unverified_fields": [
"sensor timestamp epoch",
"coordinate-frame convention",
"sensor-to-vehicle extrinsics"
],
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": true,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001",
"live-viewer-profile"
]
},
{
"id": "device.modeling.live",
"kind": "acquisition-telemetry",
"direction": "device-report",
"topic": "lixel/application/report/modeling",
"wire_format": "protobuf ModelingReport acquisition telemetry subset",
"semantic_payload": "nonnegative MoveDistance metres, MoveSpeed metres per second, int64 ScanTime at two ticks per second, and int32 PgoProgress",
"bounds": {
"max_mqtt_payload_bytes": 65536,
"max_fields": 64,
"max_nested_fields": 16
},
"limitations": [
"ScanTime scale is exact-profile evidence and must not be generalized to other firmware.",
"Replay-to-view acceptance remains open even though retained physical runs establish units and live decoding."
],
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001",
"live-viewer-profile"
]
},
{
"id": "device.status.live",
"kind": "device-status",
"direction": "device-report",
"topic": "lixel/application/report/device_status",
"wire_format": "protobuf DeviceStatusReport acquisition lifecycle subset",
"semantic_payload": "bounded modeling-state base-offset mapping, init-ready flag, project presence and redacted identity fields",
"limitations": [
"Nested system and RTK status payloads are presence-checked but not semantically decoded.",
"ScanOver and Ready observations do not prove durable artifact save completion."
],
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001"
]
},
{
"id": "device.heartbeat.live",
"kind": "heartbeat",
"direction": "device-report",
"topic": "lixel/application/report/heartbeat",
"wire_format": "opaque bytes",
"semantic_payload": null,
"limitations": [
"Only channel presence and approximate report cadence are verified.",
"Payload semantics are not decoded."
],
"evidence": {
"observed": true,
"decoded": false,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001"
]
},
{
"id": "camera.preview.live",
"kind": "camera-preview",
"direction": "device-report",
"discovery_status": "observed",
"topic": null,
"endpoint_templates": [
"rtsp://{confirmed-device-private-ipv4}:8554/live/chn_left_main",
"rtsp://{confirmed-device-private-ipv4}:8554/live/chn_right_main"
],
"wire_format": "RTSP 1.0, interleaved RTP/TCP, H.264 PT96 at 90000 Hz",
"semantic_payload": "compressed live left/right camera preview selected by endpoint",
"limitations": [
"No full-resolution raw frame, camera calibration or panorama-stitching contract is verified.",
"Left/right optical identity is supported by endpoint labels and operator-selected application views, not an independent image-content fixture.",
"Mission Core implements bounded copy-remux, archival and replay admission, but no newly archived physical K1 camera session has passed shared-timeline playback acceptance."
],
"evidence": {
"observed": true,
"decoded": false,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"lab-002"
]
}
],
"acquisition_control": {
"mode": "operator-manual",
"write_enabled": false,
"software_acceptance_transport": {
"status": "installed-operator-present",
"default_authority": "disabled",
"profile_gate": "live-device-info-exact-match",
"dialogue": "single-socket-canonical-start-to-stop",
"automatic_retry": false,
"supported_mount_type": "handheld",
"supported_gnss_mode": "none"
},
"verified_device_control": {
"gesture": "physical-double-click",
"state_dependent_result": "start from steady-green standby; stop during active scanning",
"single_click_result": "not a verified scan-start action",
"evidence": {
"observed": true,
"decoded": false,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"lab-001"
]
},
"semantic_actions": [
{
"id": "acquisition.start",
"execution": "operator-manual",
"operator_control": "physical-double-click from steady-green standby",
"observed_application_control": "owner-operated LixelGO project confirmation",
"vendor_request_mapping": {
"evidence_kind": "owner-controlled-wire-observation",
"transport": "MQTT 3.1.1",
"topic": "lixel/application/request/modeling",
"qos": 2,
"retain": false,
"message_type": "ModelingRequest",
"action_field_value": 1,
"header_contract": {
"device_id": "explicit-observed-identity",
"session_id": "{device_id}:ModelingRequest",
"openapi_key": "private-application-level-runtime-authority"
},
"request_fields": {
"project_name": "required-operator-value",
"record_mode": 2,
"scan_mode": 1,
"mount_type": 0,
"pre_project_id": "omitted-in-retained-request"
},
"success_result_code": 302252033,
"required_unresolved_context": [
"operator-owned Keychain authority provisioning and operator-present physical acceptance",
"authorization policy for any setting outside the retained request",
"timeout, rejection and rollback contract"
],
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"write_enabled": false
},
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001",
"lab-002"
]
},
{
"id": "acquisition.stop",
"execution": "operator-manual",
"operator_control": "physical-double-click during active scanning",
"observed_application_control": "owner-operated LixelGO stop confirmation",
"vendor_request_mapping": {
"evidence_kind": "owner-controlled-wire-observation",
"transport": "MQTT 3.1.1",
"topic": "lixel/application/request/modeling",
"qos": 2,
"retain": false,
"message_type": "ModelingRequest",
"action_field_value": 2,
"header_contract": {
"device_id": "explicit-observed-identity",
"session_id": "{device_id}:ModelingRequest",
"openapi_key": "private-application-level-runtime-authority"
},
"request_fields": {},
"success_result_code": 302252033,
"required_unresolved_context": [
"operator-owned Keychain authority provisioning and operator-present physical acceptance",
"save-completion and final-standby state mapping",
"timeout and rollback contract"
],
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"write_enabled": false
},
"evidence": {
"observed": true,
"decoded": true,
"replay_verified": false,
"physical_verified": true,
"write_enabled": false
},
"source_ids": [
"mqtt-stream-profile",
"lab-001",
"lab-002"
]
},
{
"id": "calibration.device.start",
"execution": "unavailable",
"operator_control": null,
"vendor_request_mapping": null,
"observed_behavior": "Static initialization follows acquisition.start; no independent calibration action was observed.",
"limitations": [
"No standalone calibration command topic, request schema, acknowledgment or state transition is verified."
],
"evidence": {
"observed": false,
"decoded": false,
"replay_verified": false,
"physical_verified": false,
"write_enabled": false
},
"source_ids": [
"lab-002"
]
}
]
}
}