feat(lab): add isolated iPhone capture evidence
This commit is contained in:
@@ -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 60–180 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 23–25 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,500–2,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.45–6.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.
|
||||
Reference in New Issue
Block a user