feat(lab): add isolated iPhone capture evidence

This commit is contained in:
DCCONSTRUCTIONS
2026-07-16 19:43:41 +03:00
parent 63dd8c8790
commit 19ab973110
11 changed files with 2428 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
# LixelGO / iPhone observation runbook
This runbook prepares the Mac without full Xcode and defines the first bounded,
read-only capture. The accepted decision is ADR 0005. Do not start the iPhone
experiment until the exact-profile physical regression in ADR 0004 passes.
## Current Mac baseline
- macOS 26.5.1, Apple Silicon;
- Xcode Command Line Tools 16.4 are present;
- full Xcode and `rvictl` are absent;
- built-in `tcpdump` and `uv` are present;
- Wireshark/tshark are not required for capture;
- the isolated lab uses Python 3.12 and `pymobiledevice3==9.36.0`.
## Preparation
```bash
uv sync --project plugins/xgrids-k1/lab/iphone-capture --frozen
uv run --project plugins/xgrids-k1/lab/iphone-capture --frozen \
pymobiledevice3 version
```
Expected version: `9.36.0`.
Connect one unlocked iPhone using a data cable, approve the Mac accessory prompt,
and tap **Trust This Computer**. Do not paste a UDID into Terminal or notes.
```bash
uv run --project plugins/xgrids-k1/lab/iphone-capture --frozen \
python plugins/xgrids-k1/lab/iphone-capture/preflight.py
```
## First smoke without K1
After the iPhone preflight succeeds, run a 10-second idle capture only after the
current source milestone is committed or with an explicitly recorded dirty-tree
fingerprint:
```bash
uv run --project plugins/xgrids-k1/lab/iphone-capture --frozen \
python plugins/xgrids-k1/lab/iphone-capture/capture.py \
--duration 10
```
The tool retains the original metadata-bearing `PCAPNG` and creates a compatible
classic `PCAP`. Validate the latter with built-in `tcpdump`:
```bash
tcpdump -nn -r sessions/iphone-k1-observation/<session>/captures/iphone-network.pcap -c 1
```
After the capture and operator timeline are both closed, seal the complete
session without rewriting the capture manifest:
```bash
uv run python plugins/xgrids-k1/lab/iphone-capture/session_integrity.py \
sessions/iphone-k1-observation/<session>
```
The derived private inventory verifies all manifest hashes and also hashes the
late operator-event artifact when it exists.
## Full baseline sequence
1. Complete the ADR 0004 physical K1 regression without LixelGO.
2. Close unrelated iPhone apps and pause unrelated network activity.
3. Keep the iPhone on the K1/shared Wi-Fi while USB remains connected to Mac.
4. Start a bounded 60180 second network capture.
5. Perform one predefined LixelGO action at a recorded monotonic offset.
6. Stop and retain the raw capture; analyze only offline.
7. Record endpoints, ports, sizes, timing and correlation before interpreting a
payload as a command, image, or model frame.
The first baseline does not install the Bluetooth logging profile. BLE/HCI is a
separate operator-approved experiment.
@@ -0,0 +1,76 @@
# ADR 0005: Owner-controlled LixelGO/iPhone observation
- Status: accepted
- Date: 2026-07-16
- Supersedes: only the unavailable-phone assumption in ADR 0001
## Context
ADR 0001 correctly described the original stand: no phone and no LixelGO were
available, so they could not be dependencies or test oracles. An
owner-controlled iPhone with LixelGO is now available for a new, evidence-only
experiment. The previous no-phone results remain valid historical evidence.
An ordinary third client on the mesh Wi-Fi cannot normally observe unicast
traffic between the iPhone and K1. Apple's native Remote Virtual Interface path
requires `rvictl`, which is installed by full Xcode and is absent from the
current Mac. Installing full Xcode solely for the first capture is unnecessary.
## Decision
The XGRIDS plugin may use a pinned, isolated `pymobiledevice3` lab environment
to read the iPhone `pcapd` service over a trusted USB connection. This mirrors
the iPhone IP stack while the phone remains connected to K1 over Wi-Fi. It is a
lab subprocess, not a root Mission Core dependency.
The experiment is evidence-only:
- no TLS interception or MITM certificate;
- no app automation;
- no new BLE or MQTT write;
- no router, firmware, device-file, or application mutation;
- no camera or command semantic claim until bounded decode and a controlled
physical correlation are both present.
Network capture does not include BLE HCI. Bluetooth capture is a separate gate
that requires Apple's diagnostic logging profile, explicit operator approval,
and removal of that profile after the experiment.
All captures are sensitive, mode `0600`, bounded in duration, stored under
ignored `sessions/`, hashed, and represented in Git/Ops only by redacted facts.
No device ID, credential, SSID, router metadata, or raw packet payload enters
normal Git history.
## Entry gate
LixelGO/iPhone observation starts only after ADR 0004's post-refactor physical
regression succeeds on exact firmware `3.0.2` and direct-LAN:
1. operator attestation;
2. prepare the receiver;
3. physical double-click start;
4. first real point frame and pose through the new normalizer/viewer path;
5. raw evidence finalization;
6. operator-confirmed physical stop;
7. verification that Mission Core emitted no K1 application command.
## Consequences
Full Xcode, `rvictl`, Wireshark, and system/Homebrew changes are not required for
the first IP capture. TLS or proprietary encryption may remain opaque; endpoint,
port, size, timing, interface, process, and plaintext local protocol evidence are
still useful. Any discovered state-changing contract requires a new profile
revision and its own acceptance gate before implementation.
## Outcome recorded on 2026-07-16
Lab 002 completed the bounded observation. It found a plaintext local MQTT data
and control plane plus two RTSP/H.264 camera preview endpoints. Owner-operated
LixelGO start and stop were correlated with bounded protobuf action values `1`
and `2`, device success responses, physical K1 transitions and start/stop of the
high-rate streams. No LixelGO WAN flow was observed in either principal window.
This outcome updates descriptive evidence only. Mission Core still emits no
modeling request: private header/settings construction, save-complete semantics,
timeouts and rollback remain unresolved. See
`docs/lab/002_LIXELGO_IPHONE_LOCAL_PROTOCOL_20260716.redacted.md`.
@@ -0,0 +1,180 @@
# Lab 002 — LixelGO/iPhone local K1 protocol observation
- Date: 2026-07-16
- Device scope: one owner-controlled LixelKity K1, exact firmware `3.0.2`
- Application scope: owner-operated LixelGO on a trusted iPhone
- Capture path: iPhone `pcapd` over USB to the Mac
- Result: **GO for protocol-backed camera discovery and start/stop mapping;
PAUSE for Mission Core command emission and save-state semantics**
This report contains no device identifier, address, SSID, credential, project
name, room image, or raw packet payload. The sensitive source captures remain
under ignored `sessions/` with mode `0600`.
## Experiment boundary
The operator performed one clean LixelGO lifecycle and one control/stop window:
1. K1 was powered to steady-green standby without a physical scan gesture.
2. LixelGO established Bluetooth control and requested the K1 Wi-Fi network.
3. The operator accepted the iOS Wi-Fi join request.
4. LixelGO entered its scan workspace; this navigation alone caused no K1 state
transition.
5. The operator supplied a private project name and confirmed start.
6. K1 performed static initialization and exposed point cloud, pose and camera
preview.
7. The operator selected left and right camera views.
8. The operator opened the stop confirmation and then confirmed it.
9. K1 stopped the LiDAR, displayed its saving state and returned to steady-green
standby without any physical K1 button press.
Bluetooth HCI was not captured. The BLE stage is supported by the operator's
screen/physical observation, while all protocol findings below start at the
iPhone IP stack.
## Evidence integrity
The two principal network sessions contain `108,188` and `207,123` packets.
Their raw PCAPNG and compatible classic PCAP hashes match the capture manifests,
and packet timestamps/order are equivalent across the two representations.
The original manifests and captures were left byte-for-byte unchanged. A
separate private integrity inventory re-hashes the manifests, packet files and
late operator-event JSONL. Operator events record sequence, not precise action
latency: several were narrated after the corresponding wire event.
## Network and privacy result
LixelGO accounted for more than `99.5%` of bytes in each principal capture and
communicated with exactly two private local endpoints. No LixelGO flow to a
public/WAN address was observed in either window. The first window contained a
very small amount of unrelated public traffic from other iPhone processes; the
second contained no public traffic at all.
This is bounded negative evidence for these sessions, not a permanent claim
about every application mode or future LixelGO release.
Observed K1 transports:
| Transport | Purpose | Result |
| --- | --- | --- |
| MQTT 3.1.1 over plaintext TCP `1883` | control, status, point cloud, pose | observed |
| RTSP 1.0 over TCP `8554` | left/right camera session control | observed |
| interleaved RTP/TCP, H.264 PT96, 90 kHz | camera preview media | observed |
| HTTP over TCP `80` | three empty project-related setup responses | ancillary only |
No LixelGO UDP flow was observed.
## Start and static initialization
The application start transaction is now physical wire evidence rather than
static-analysis evidence:
- QoS 2 PUBLISH topic: `lixel/application/request/modeling`;
- bounded protobuf top-level action field: `1`;
- correlated device response: about `1.5 ms` after the request, with the same
action and a success result;
- first pose: about `23.1 s` after the request;
- first modeling/point-cloud reports: about `24.1 s` after the request;
- first camera RTSP PLAY: about `25.1 s` after the request.
The observed 144-byte START protobuf has this bounded top-level wire shape
(private strings remain redacted):
```text
f1/wire2 = 130-byte private header/session string
f2/wire0 = 1
f3/wire2 = 3-byte private string
f4/wire0 = 2
f5/wire0 = 1
```
`f4` is the decoded value `2`; the occasionally noted `1` describes only the
one-byte varint encoding length and is not the field value. The successful
response repeats the private 130-byte field, reports `f2=1`, and includes an
observed success block in `f15/wire2` (15 bytes). These observations describe
the capture but do not establish safe construction rules for a new request.
The 2325 second interval matches the operator-observed static initialization.
The captured request contains additional private header/settings context. Its
complete construction and validation rules remain unresolved and are not
committed as a reusable command fixture.
## Live data plane
The existing repository decoder successfully decoded distributed samples of
both live spatial channels:
- point cloud: `lixel/application/report/lio_pcl`, about `9.4 Hz`, roughly
`2,5002,650` points per sampled frame;
- pose: `lixel/application/report/lio_pose`, about `10 Hz`, finite decoded
position/orientation fields.
During active scanning the aggregate K1-to-phone data plane averaged roughly
`1.11 MB/s`, split approximately into `0.25 MB/s` MQTT and `0.86 MB/s` camera
RTSP/RTP. The observed peak was about `1.89 MB/s`.
## Camera preview
The K1 exposes two independent path-labelled RTSP preview endpoints:
```text
rtsp://{confirmed-device-private-ipv4}:8554/live/chn_left_main
rtsp://{confirmed-device-private-ipv4}:8554/live/chn_right_main
```
Each session follows `OPTIONS`, `DESCRIBE`, `SETUP`, `PLAY`; media is H.264 in
interleaved RTP over TCP. The observed preview rate was approximately `10 fps`
and `6.456.59 Mbit/s`.
Camera selection is not an MQTT command. LixelGO tears down the current RTSP
session and opens the other endpoint. In the controlled left-to-right switch,
the new RTSP connection began about `0.8 s` after the preceding stream's last
packet. RTP arrived immediately after PLAY, but the first new SPS/PPS/IDR group
arrived about `0.79 s` later. This explains most of the operator-observed visual
delay; exact tap-to-display latency was not measurable from retrospective event
markers.
The capture proves a compressed preview path, not full-resolution raw camera
frames, camera calibration, stitched panorama geometry, or optical left/right
identity beyond the endpoint labels and operator-selected views.
## Stop and post-stop boundary
The remote stop transaction is also verified inside the packet capture:
- QoS 2 PUBLISH on the same modeling-request topic;
- bounded protobuf top-level action field: `2`;
- correlated success response after about `33 ms`;
- final point-cloud PUBLISH after about `36.4 ms`;
- final pose PUBLISH after about `40.8 ms`;
- final interleaved video packet after about `54.1 ms`;
- point-cloud UNSUBSCRIBE and RTSP TEARDOWN at about `0.95 s`;
- status/modeling reports for about another `9 s`;
- control MQTT and heartbeat remained reachable for about `31 s` without a
recurrence of high-rate point, pose, or video traffic.
The raw modeling-state value changed immediately after stop. Its enum name is
not decoded. The capture does not contain an independently verified
`save-complete`/`project-closed` response or the previously observed standby
state code. Completed saving and final steady-green standby are therefore
operator-corroborated, not packet-semantically proven.
## Decision
- **GO:** retain MQTT point cloud and pose as the current live spatial plane.
- **GO:** implement a read-only left/right RTSP/H.264 preview receiver behind
the XGRIDS plugin boundary.
- **GO:** promote start=`1` and stop=`2` from static hints to observed,
physical-correlated vendor mappings.
- **PAUSE:** keep all Mission Core vendor writes disabled until request headers,
settings, acknowledgements, timeout, save completion and rollback are modeled
and regression-tested.
- **PAUSE:** do not name the post-stop enum or claim durable project persistence
from this capture.
- **PAUSE:** BLE automation remains governed by the separately reviewed Wi-Fi
provisioning profile; no BLE/HCI inference is added here.
The next smallest implementation step is an offline/then-live read-only camera
adapter with bounded buffering, H.264 metadata, explicit left/right selection
and no acquisition command publisher.