Appendix · story

Work log: phone-unavailable bench prep

What landed while the PinePhone Pro was unavailable, and what each piece still needs from hardware.

This is the short journal for the no-phone stretch on 2026-05-01. The theme was not to invent new untestable hardware claims. The useful work was to make the next phone session short, logged, and falsifiable.

2026-05-01 early session

The vibration motor moved from a DTS guess to a real FreeBSD candidate: gpio_vibrator(4) attaches to the standalone pinephonepro-vibrator node, advertises EV_FF / FF_RUMBLE, and exposes passive sysctls for active, play_count, stop_count, last_error, and suspend/resume state. 5e5c8f8 vibrator: add gpio rumble candidate added the driver and evdev force-feedback plumbing. d3857f0 vibrator: add rumble bench verifier added the userland rumble verifier. e3b9325 vibrator: quiesce on suspend added suspend quiesce so a motor cannot stay enabled across a sleep transition.

2026-05-01 early session

Two camera-adjacent flash paths got bench helpers. The SGM3140 helper keeps the default mode status-only, then offers bounded torch and flash pulses when explicitly requested. 47cd7e0 sgm3140: add bounded flash bench helper added the helper, and the later bench-analyzer pass gave its status path stable PASS/WARN markers.

The GD25LQ128 SPI NOR work got a read-only verifier instead of another note-to-self. b957995 gd25lq128: add read-only bench verifier reads the rk2aw/idbloader and U-Boot FIT offsets through /dev/flash0, hashes the samples, rejects all-zero bootloader data, and checks the FIT magic at sector 20480.

2026-05-01 late session

The sensor receipt became one command. 70763a9 sensors: add combined phone receipt replaced the old two-sensor status script with mise run debug:sensors:phone, a combined read-only receipt for STK3311, MPU-6500, magnetometer, RK3399 TSADC, and RK3399 eFuse. It prints raw sysctl trees plus a compact predicate block: attached, expected IDs, plausible ranges, last_sample_error, and TSADC shutdown state.

2026-05-01 late session

The per-component receipts were wrapped into a phone bench bundle. 9009f9f bench: add phone receipt bundle added mise run bench:phone, which writes timestamped logs under logs/phone-bench/<timestamp>-<name>/. The default path is non-destructive: sensors, SPI NOR read-only verifier, SGM3140 status, and modem status. Physical outputs stay behind --with-actuators, which adds vibrator rumble and bounded SGM3140 pulse checks.

41c2bfa bench: add phone receipt analyzer added mise run bench:phone:analyze and made the bench runner emit analysis.txt automatically. The analyzer turns the saved bundle into a PASS/WARN/MISSING/FAIL table so the next hardware session starts with a one-screen receipt rather than a pile of logs.

2026-05-01 late session

The next requested step was a Coppice build smoke for current master. The local Coppice CLI was not installed, so the run used the gateway API at http://192.168.122.181:3000 directly. Auth was disabled, /templates reported only python-bhyve, and /snapshots reported three python-bhyve checkpoints. Cold create, snapshot fork, and a jail-template probe all failed to produce a live sandbox: the gateway tasks stayed at backend create started / backend fork started with no entry in GET /sandboxes. The stuck tasks were cancelled through POST /tasks/:id/cancel.

The local receipt for the blocked substrate attempt is logs/coppice-build/20260501-024215-coppice-substrate-blocked.log. Node2 showed the same behavior against its own gateway and was captured in logs/coppice-build/20260501-024357-coppice-node2-substrate-blocked.log.

2026-05-01 follow-up

Coppice came back far enough to run real build work. mise run coppice:preflight succeeded against both bhyve gateway nodes, and the build-smoke helper was corrected to match the honor pipeline more closely: it now fetches source archives with base fetch / tar, copies jsm222/drm-subtree before local overlays, skips package LLVM, and can run buildkernel with COPPICE_KERNEL_NO_MODULES=1 for constrained bhyve guests.

The best build attempt was on node2 in logs/coppice-build/20260501-095947-build-smoke.log. It fetched the project archive and FreeBSD stable/15, copied the DRM subtree, applied the local overlays and patches, and reached:

make -C /work/freebsd-src -DWITHOUT_CLEAN WERROR= NO_MODULES=yes -j1 buildkernel

At the last live poll it was compiling kernel objects from the PINEPHONE_PRO config with /work/freebsd-src at 1.7 GB and /work/obj started. The run ended when the Coppice gateway returned curl: (52) Empty reply from server; the sandbox was gone after the API came back. A patch-only retry on node2 later rebooted the guest mid-run, and node1 still showed resolver failures from inside the bhyve guest.

2026-05-01 follow-up

With the phone still unavailable, the next requested step was to build on honor. SSH to honor failed with No route to host for 192.168.1.149:22, so the no-phone work stayed local: source-audit the hardware map against the in-tree DTS and the component pages, then correct stale spec/status claims that would waste the next bench session.

The fixes were documentation-only in this pass: HP detect is already named in DTS on GPIO4_D4 and now correctly reads as a policy gap, not a DTS gap; TSADC/eFuse/PL330/vibrator are partial candidates rather than missing; SARADC is working, not missing; the component matrix now lists IMX258 on DTS &i2c1 addr 0x1a; the FUSB302 note now says DTS &i2c4 addr 0x22 / FreeBSD shifted addr 0x44 on iicbus3; and the broad root summary no longer publishes stale exact totals.

2026-05-01 follow-up

The Coppice build smoke now survives a full PINEPHONE_PRO kernel compile. fda814e build: detach coppice kernel smoke changed tools/coppice-build-smoke.sh so long kernel builds run detached inside the bhyve guest and the local task polls /work/logs/coppice-build.log through short execs. That avoided the gateway empty-reply failure mode without losing the build transcript.

The first detached full-kernel run reached the final link and exposed a real source issue instead of an infrastructure issue: fusb302.o referenced rk818_charger_set_input_current_ma, but rk818_battery.c was not listed in sys/conf/files.arm64. 41aead6 build: include rk818 charger helper adds the helper object to the arm64 file list. The retry in logs/coppice-build/20260501-105104-build-smoke.log fetched commit 41aead6, applied Honeyguide + DRM + local overlays + patches, and completed:

PASS: Coppice build smoke completed
2026-05-01 follow-up

The next Coppice improvement is snapshot reuse, so fresh sandboxes do not repeat the slow FreeBSD and DRM archive setup. mise run coppice:prepare-snapshot now creates a bhyve sandbox, caches FreeBSD stable/15 and jsm222/drm-subtree under /work/cache, snapshots that prepared filesystem, and deletes the source sandbox. coppice:build-smoke then recognizes /work/cache/freebsd-src and /work/cache/drm-subtree in a forked snapshot, while still fetching the current pine64-freebsd archive for each run.

The first prepared source-cache snapshot is 903b69a29ce3, from logs/coppice-build/20260501-110823-prepare-snapshot.log. A forked patch smoke in logs/coppice-build/20260501-111422-build-smoke.log confirmed the cache path:

== copying cached FreeBSD source archive ==
== copying cached drm-subtree ==
PASS: coppice build smoke completed

Current Snapshot

AreaCurrent stateNext hardware proof
Vibration motor ◐ partial driver + EV_FF verifier + suspend quiescedebug:vibrator:rumble passes and the motor physically moves
GD25LQ128 SPI NOR ◐ partial table patch + read-only boot-region verifier/dev/flash0 attaches and FIT magic is read at 0xa00000
SGM3140 flash LED ◐ partial status helper + bounded pulse helper/dev/led/flash and /dev/led/torch exist; opt-in pulse visibly fires
Magnetometer ◐ partial polled raw axis driver candidateAF8133J at DTS &i2c4 addr 0x1c reports chip_variant=af8133j and last_sample_error=0
TSADC ◐ partial sysctl driver with hardware shutdown disarmedidle temperatures are plausible and no false shutdown occurs
eFuse ◐ partial sysctl-only cells exposedcpu_id and leakage bytes match Linux nvmem readout
Bench bundle ◐ partial runner and analyzer are local-testedone full bench:phone bundle from a patched kernel
Coppice build smoke ● working detached full-kernel smoke builds PINEPHONE_PRO in bhyve with NO_MODULES=yes; source-cache snapshot 903b69a29ce3 avoids refetching FreeBSD/drmlarger template or attached work disk for module builds and retained object trees

The next phone session should start with:

mise run bench:phone -- --name fresh-kernel
mise run bench:phone:analyze

Only after the read-only/default bundle is understood should the physical checks run:

mise run bench:phone -- --name actuator-pass --with-actuators