# Contributing to Punktfunk

Thanks for your interest in contributing!

## Licensing of contributions (inbound = outbound)

Punktfunk is dual-licensed under **MIT OR Apache-2.0**.

> Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
> the work by you, as defined in the Apache-2.0 license, shall be dual licensed as **MIT OR
> Apache-2.0**, without any additional terms or conditions.

By opening a pull request you agree to license your contribution under these terms. This is the
standard Rust-ecosystem "inbound = outbound" model; it keeps the project's licensing unambiguous
(including the Apache-2.0 §5 contributor patent grant) and any future relicensing clean. You retain
the copyright to your contributions.

### Do not paste copyleft (or otherwise incompatibly-licensed) code

The single thing that could poison the permissive license is **copied source from a copyleft
project**. Several adjacent projects (Sunshine, Apollo, Moonlight) are GPL-3.0. You may study them
and reimplement a *technique*, protocol, or wire format — those are not copyrightable — but **never
paste their code**, and do not translate a GPL implementation line-by-line. When a comment credits
prior art, make clear it is an independent reimplementation, not a copy. The same applies to any
third party's code under a license incompatible with MIT/Apache.

If you add a new third-party dependency, it must be permissive (MIT / Apache-2.0 / BSD / ISC / Zlib /
Unicode-3.0 / etc.). `about.toml` holds the accepted-license allow-list; regenerate the attribution
file with `scripts/gen-third-party-notices.sh` when the dependency tree changes.

## Prerequisites

The Rust toolchain is **pinned exactly** in `rust-toolchain.toml`; rustup installs it for you the
first time you build, so don't override it — a different rustc reformats files nobody touched.

The workspace links real system libraries, so a bare `cargo build --workspace` fails on a stock
machine. The authoritative list is what CI installs, in `ci/rust-ci.Dockerfile` — on **Ubuntu 26.04**,
which is what gets you FFmpeg 8:

```sh
sudo apt install build-essential clang libclang-dev pkg-config cmake \
  libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavfilter-dev libavdevice-dev \
  libpipewire-0.3-dev libopus-dev libwayland-dev libxkbcommon-dev \
  libgl-dev libegl-dev libgbm-dev \
  libgtk-4-dev libadwaita-1-dev libsdl3-dev \
  libvulkan-dev
```

(The last two groups are the Linux client shell and `pf-ffvk`; skip them only if you never build
those crates. `scripts/bootstrap-ubuntu.sh` sets up an Ubuntu **capture-test host** — NVIDIA, Sway,
PipeWire — and is not a substitute for the list above.)

## Before you push

Enable the repo git hooks once per clone — they run the exact rustfmt gates CI runs (main
workspace + the UMDF driver workspace) on every commit and push, so a push can never fail CI
on formatting alone:

```sh
git config core.hooksPath scripts/git-hooks
```

Then the usual full pass. Use `--locked` as CI does — otherwise a silent `Cargo.lock` update can pass
locally and fail CI:

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

Two more gates that only apply to some changes:

- **Touched `web/` or `docs-site/`?** CI builds and typechecks both. Run, in that directory:
  ```sh
  bun install && bun run build && bun run lint
  ```
  Build first — it generates the API client / MDX typegen that the typecheck imports.
- **Touched Windows- or Linux-gated code from another OS?** `scripts/xcheck.sh windows` (or
  `linux`) type-checks and lints that platform's `#[cfg(target_os = …)]` code in about a second,
  instead of waiting for the CI job that compiles it.

Generated artifacts are checked in. `include/punktfunk_core.h` (cbindgen) is regenerated by the build
and CI fails if the committed copy drifts. `api/openapi.json` is **not** gated — nothing in CI
regenerates or diffs it, so regenerate and commit it yourself whenever you touch the management API,
and copy the snapshot the docs site serves:

```sh
cargo run -p punktfunk-host -- openapi > api/openapi.json
cp api/openapi.json docs-site/public/openapi.json
```

Match the surrounding code's comment density and naming. Commit messages end with the
`Co-Authored-By` trailer (see `git log`).

See the [README's Build & test section](README.md#build--test-from-source) for the extra dev
commands (the FEC loss harness, the standalone C-ABI proof) and
[Design invariants](README.md#design-invariants) for the rules a change is expected to hold to, and
the [docs site](https://docs.punktfunk.unom.io) for architecture and per-platform guides.
