Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
each MR states scope, verification, and any hardware action needed.
- Never edit, commit, or push `main` directly. Work on a dedicated branch and
merge through a reviewed MR. Do not push any branch unless explicitly asked.
- Prefer short, descriptive branch names so manual pushes stay easy.
- Run mock/unit tests before hardware tests.
- Hardware validation runs on target Linux hardware; QEMU cannot validate USB
control behavior.
Expand Down
29 changes: 21 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
## Prerequisites

- Native Linux with a C toolchain (`cc`) for Rust crates that compile native
code. Raspberry Pi OS accessed over SSH is the primary development target;
Zed Remote Development builds and runs code on the Pi.
code. Raspberry Pi OS local sessions are the primary development target.
SSH and Zed Remote Development are optional; when used, builds and hardware
commands still run on the Pi.
- [rustup](https://rustup.rs/). The committed `rust-toolchain.toml` installs the
selected compiler, Clippy, and rustfmt.

Expand Down Expand Up @@ -43,20 +44,32 @@ install `usbutils` and `alsa-utils`.
rustup show
```

## Develop on the Pi over SSH
## Develop directly on the Pi

Clone the repository on the Pi under the SSH development user. Open that clone
through Zed Remote Development; editor, Cargo, and hardware commands then run
natively on the Pi. This is preferred even when editing from another laptop,
because it validates the actual target architecture and ALSA environment.
Work in the repository from a local Pi session. Editor, Cargo, and hardware
commands run natively on the Pi, validating target architecture and ALSA.
SSH/Zed Remote Development may access that same checkout when convenient, but
is not required.

Before connecting hardware, run the checks in [Checks](#checks). If ALSA access
is needed, add the SSH user to the `audio` group, then reconnect the SSH session:
is needed, add the current local user to the `audio` group, then start a new
login session:

```sh
sudo usermod -aG audio <user>
```

Before hardware probes, confirm the new session has both ALSA device nodes and
effective group membership:

```sh
test -d /dev/snd
id -nG
```

Do not use `sudo` to mask a missing `/dev/snd` directory or inactive `audio`
membership; fix local device-node/session access first.

Do not run control writes, routing/clock changes, firmware updates, resets, or
profile application without explicit approval.

Expand Down
5 changes: 3 additions & 2 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

- Primary appliance: Raspberry Pi 5, 64-bit Linux,
`aarch64-unknown-linux-gnu`.
- Primary development target: Raspberry Pi 5 over SSH, commonly through Zed
Remote Development.
- Primary development target: local Raspberry Pi 5 session.
- SSH and Zed Remote Development are optional remote access paths, not required
development workflow.
- Laptop-local Linux or WSL are optional development environments; neither is a
deployment target.

Expand Down
88 changes: 83 additions & 5 deletions docs/phases/phase-3-pi-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## Status

In progress. MR 1 complete; MR 2 is next. Target is prepared Pi OS ARM64 with
Scarlett Solo 4th Gen connected directly by USB. Phase 2 WSL evidence remains
valid only for its WSL scope.
In progress. MR 1 and MR 2 complete; MR 3 is next. Target is prepared Pi OS
ARM64 with Scarlett Solo 4th Gen connected directly by USB. Phase 2 WSL
evidence remains valid only for its WSL scope.

## Goal

Expand Down Expand Up @@ -89,6 +89,84 @@ FOCUSRITED_HARDWARE_CARD=Gen cargo test -p focusrited --test scarlett2_alsa \

Read-only only. No control write or stored-profile apply.

**Execution plan**

1. On the prepared Pi, confirm the Solo is directly connected and record only
bounded, sanitized read-only evidence:

```text
uname -a
lsusb | grep -i focusrite
cat /proc/asound/cards
arecord -l
aplay -l
amixer -c CURRENT_CARD_INDEX controls
amixer -c CURRENT_CARD_INDEX contents | sed -n '1,400p'
```

Replace `CURRENT_CARD_INDEX` with the index shown for Solo in the immediately
preceding `/proc/asound/cards` output; never assume card 0. Use its named
ALSA ID (for example, `Gen`) for `focusrited --card` and hardware-test
`FOCUSRITED_HARDWARE_CARD`. Redact serials, usernames, LAN addresses,
tokens, and unrelated USB/system data before saving any evidence.
2. Build and run local checks before touching Pi hardware:

```text
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
```

3. Run the ignored read-only discovery test against that explicit card:

```text
FOCUSRITED_HARDWARE_CARD=CARD cargo test -p focusrited \
--test scarlett2_alsa discovers_attached_solo -- --ignored --test-threads=1
```

Confirm it reports only non-writable capabilities, rejects a command
without a hardware write, and exits successfully.
4. Start daemon with an empty temporary profile-store path, observe successful
startup, then stop it without issuing a command:

```text
profile_dir=$(mktemp -d)
profile_store="$profile_dir/profiles"
timeout --signal=INT 5s cargo run -p focusrited -- --card CARD \
--profile-store "$profile_store"
rmdir "$profile_dir"
```

`timeout` ending this foreground daemon is expected. Treat a startup error,
ALSA access error, or an unexpected file left in the temporary profile store
as MR2 evidence to investigate.
5. Compare sanitized Pi controls, types, counts, and availability with
`crates/focusrited/tests/fixtures/scarlett-solo-4th-gen.md`. Change fixture
or parsing only for a Pi-proven difference; otherwise add a dated evidence
summary and Pi prerequisites to the hardware/deployment documentation.

**Evidence — 2026-07-17 (complete)**

- Target reports Debian GNU/Linux 13.6 on `aarch64`, kernel
`6.12.62+rpt-rpi-2712`.
- `/proc/asound/cards` identifies Scarlett Solo 4th Gen as card index 2 with
ALSA ID `Gen`. Capture and playback both expose device 0.
- Direct Pi ALSA access has `/dev/snd` available and effective `audio` group
membership. The workspace sandbox intentionally does not mount `/dev/snd`;
hardware commands must run from a direct Pi terminal or an approved
unsandboxed runner.
- Bounded `amixer -c 2 controls` and contents report 56 controls. Their IDs,
types, access shape, enum domains, and integer ranges match Phase 2 fixture.
Current control values were observed only and are not recorded here.
- `FOCUSRITED_HARDWARE_CARD=Gen` read-only `discovers_attached_solo` passes:
all discovered capabilities remain non-writable and service commands are
rejected before hardware write.
- `focusrited --card Gen` starts successfully for five seconds with an empty
disposable profile-store path. It receives no command; temporary directory
removal confirms no profile file was written.
- No ALSA control, profile, fixture, or adapter code changed. MR3 may capture
metadata and verify an operator-initiated external Direct Monitor change.

### MR 3: Native reconciliation and controlled write metadata

**Scope**
Expand Down Expand Up @@ -153,8 +231,8 @@ Read-only only.

- [x] Read-only and write-capable hardware tests are structurally separated;
write tests require explicit feature plus session approval.
- [ ] Solo service builds and starts natively on Pi against selected ALSA card.
- [ ] Sanitized Pi discovery proves capabilities and documented prerequisites.
- [x] Solo service builds and starts natively on Pi against selected ALSA card.
- [x] Sanitized Pi discovery proves capabilities and documented prerequisites.
- [ ] External/front-panel change reconciles into authoritative service state.
- [ ] Physical unplug/replug recovers to a fresh online snapshot.
- [ ] Pi reboot returns daemon and Solo readiness without device-state mutation.
Expand Down
8 changes: 5 additions & 3 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,18 @@ domains remain explicit but non-writable.
Exit: mock and Solo-on-WSL tests cover supported control behavior, failure,
disconnect/reconnect, and persistence; unsupported controls are explicit.

## Phase 3: Pi compatibility verification — planned
## Phase 3: Pi compatibility verification — in progress

Execution plan: [Phase 3 Pi compatibility plan](phases/phase-3-pi-compatibility.md).

Develop directly on the Pi over SSH, including Zed Remote Development from a
laptop, then validate current Solo service natively on Pi Linux. Find and fix
Develop directly in a local Pi session, then validate current Solo service
natively on Pi Linux. SSH/Zed Remote Development is optional. Find and fix
target-only build, ALSA, USB, system-service, reboot, and unplug/replug issues.
Cross-compilation may be introduced only if native Pi development demonstrates a
real need.

MR 1 and MR 2 are complete; MR 3 is next.

Before adding Phase 3 hardware coverage, split Solo tests into a read-only
hardware suite (discovery, external changes, reconnect) and a write-capable
suite. Gate the write-capable suite behind an explicit Cargo feature so running
Expand Down
Loading