Finishes the rust-safety programme's §4 WP2 from design/rust-safety-lint-ratchets-handoff.md. Moves the primary unsafe metric by ~zero, by design — everything here is a permanent structural control that stops new undisciplined code accruing.
The three crate-level gaps (WP2b) — 23fa03b0
pf-vkhdr-layer — the sharpest gap: a Vulkan implicit layer injected into every Vulkan game process, 32 unsafe usages, zero SAFETY comments, its own workspace so no lint table reached it, plus an explicit missing_safety_doc allow. Now: a [lints] table (unsafe_op_in_unsafe_fn + clippy::undocumented_unsafe_blocks, both deny), every unsafe operation in an explicit block with a written proof (loader layer protocol / Vulkan valid-usage / the two hand-computed struct offsets), # Safety docs on the contract-carrying fns, const layout asserts on the SurfaceFormat2Raw mirror, five contract-free helpers demoted to safe fns, and both redundant unsafe impl Send deleted (fn pointers are Send intrinsically — the type-check proves it).
wdk-probe — the 9 missing SAFETY proofs written (the iddcx_rt.rs DDI slot-dispatch ones argue table population and PFN/index pairing, not pattern fill), sibling denies added, and the crate joins windows-drivers.yml's clippy list — it was the only driver crate not in it.
pf-clipboard — the deny moves from host/windows.rs to the crate root, so wayland.rs, mutter.rs, and any future backend under host/ are covered on creation. Free today (all six blocks already carried proofs).
The hoist (WP2c part 1) — dfebb9df + 5f097d53 + abec2a14
undocumented_unsafe_blocks = "deny" joins unsafe_op_in_unsafe_fn in [workspace.lints], and ~100 scattered per-file #![deny(...)] attributes across 85 files are deleted. There are three workspaces, so the claim is made three times (main, packaging/windows/drivers + [lints] workspace = true in all seven members, packaging/windows/pf-vkhdr-layer). pf-update now inherits workspace lints; the vendored member snapshots (cros-codecs, usbip-sim) stay out deliberately and both now say so. Newly-covered fallout: two link-sanity tests (proofs written) and the two bindings-only sys crates (bindgen output in OUT_DIR can't carry hand-written proofs — crate-wide allow with rationale).
nvenc_core.rs is carved out of the unsafe_op_in_unsafe_fn fence: its exemption rationale ("raw entry-table calls almost line for line") was false — the file makes zero FFI calls. It now runs the strictest discipline in the crate: clippy::multiple_unsafe_ops_per_block at deny, every union read/borrow/bitfield-setter call in its own block naming its codec guard — exactly the surface the shipped 4:4:4 bug (hevcConfig stamped onto an AV1 config) lived on. Plain union-arm writes stay bare: the .25 gate corrected me — they're safe by language rule (the hazard is the mismatched read).
The grep gates (WP2c part 2) — 2bfd1cd2, blocking in ci.yml
scripts/ci/check-unsafe-hygiene.sh, three classes no lint covers:
A. unsafe fn markers carrying no contract (the db659809 class). Waivable for contract-deferring fns (set_len shape) with // unsafe-fn-no-op-ok: <reason>; fenced files and signature-mandated unsafe extern "ABI" fn callbacks skipped structurally.
B. unwrap/expect/panic! in extern "C"/"system" bodies — an abort since Rust 1.81 (the 8b98d0b3 class). catch_unwind bodies exempt.
C. Process-global safe APIs (env::set_var, sigaction, …) — the 972af299 class, invisible to the unsafe census. Per-file count ratchet; any increase or new file fails.
Making gate B clean surfaced 14 real instances of exactly its class — .lock().unwrap() in unguarded extern fns, where a poisoned mutex aborts the embedding process: six punktfunk-coreabi.rs entry points, seven Android JNI entry points, and the Windows client's deeplink wnd_proc. All fixed with poison-recovering locks + Option::insert for the set-then-unwrap shape. Gate A's six findings were genuine contract-deferring fns — waived with reasons.
Gate-of-the-gate: all three shown to fail on deliberately planted instances (and re-shown after the mawk-portability rewrite — the awk originally used a gawk-only empty-separator split, which Debian's mawk would have made silently vacuous), and to run clean, before the ci.yml step made them blocking.
Verification
.25 — cargo clippy --workspace --all-targets --locked -- -D warnings exit 0 on the final tree (GTK client excluded: box lacks GTK dev packages, real CI installs them), plus the ci.yml feature-gated encode leg: clippy exit 0, 120 tests pass (covers nvenc_core under its new lint).
.133 — the full lint suite, extract-first with sentinels + cargo clean so a stale upload can't pass: all 12 steps exit 0 — host/encode (nvenc,amf-qsv,qsv), capture, vdisplay, tray, the Windows client, pf-vkhdr-layer fmt+clippy, and the drivers workspace clippy including wdk-probe under the real WDK + drivers fmt.
punktfunk-core's 203 lib tests pass locally; native macOS clippy clean for everything that compiles there (three pre-existing mac-native failures reproduce on the clean tree).
Finishes the rust-safety programme's §4 WP2 from `design/rust-safety-lint-ratchets-handoff.md`. Moves the primary unsafe metric by ~zero, by design — everything here is a permanent structural control that stops *new* undisciplined code accruing.
## The three crate-level gaps (WP2b) — `23fa03b0`
- **pf-vkhdr-layer** — the sharpest gap: a Vulkan implicit layer injected into every Vulkan game process, 32 unsafe usages, zero SAFETY comments, its own workspace so no lint table reached it, plus an explicit `missing_safety_doc` allow. Now: a `[lints]` table (`unsafe_op_in_unsafe_fn` + `clippy::undocumented_unsafe_blocks`, both deny), every unsafe operation in an explicit block with a written proof (loader layer protocol / Vulkan valid-usage / the two hand-computed struct offsets), `# Safety` docs on the contract-carrying fns, const layout asserts on the `SurfaceFormat2Raw` mirror, five contract-free helpers demoted to safe fns, and both redundant `unsafe impl Send` deleted (fn pointers are `Send` intrinsically — the type-check proves it).
- **wdk-probe** — the 9 missing SAFETY proofs written (the `iddcx_rt.rs` DDI slot-dispatch ones argue table population and PFN/index pairing, not pattern fill), sibling denies added, and the crate joins `windows-drivers.yml`'s clippy list — it was the only driver crate not in it.
- **pf-clipboard** — the deny moves from `host/windows.rs` to the crate root, so `wayland.rs`, `mutter.rs`, and any *future* backend under `host/` are covered on creation. Free today (all six blocks already carried proofs).
## The hoist (WP2c part 1) — `dfebb9df` + `5f097d53` + `abec2a14`
`undocumented_unsafe_blocks = "deny"` joins `unsafe_op_in_unsafe_fn` in `[workspace.lints]`, and ~100 scattered per-file `#![deny(...)]` attributes across 85 files are deleted. There are **three workspaces**, so the claim is made three times (main, `packaging/windows/drivers` + `[lints] workspace = true` in all seven members, `packaging/windows/pf-vkhdr-layer`). `pf-update` now inherits workspace lints; the vendored member snapshots (cros-codecs, usbip-sim) stay out deliberately and both now say so. Newly-covered fallout: two link-sanity tests (proofs written) and the two bindings-only sys crates (bindgen output in OUT_DIR can't carry hand-written proofs — crate-wide allow with rationale).
**nvenc_core.rs is carved out of the `unsafe_op_in_unsafe_fn` fence**: its exemption rationale ("raw entry-table calls almost line for line") was false — the file makes zero FFI calls. It now runs the strictest discipline in the crate: `clippy::multiple_unsafe_ops_per_block` at deny, every union read/borrow/bitfield-setter call in its own block naming its codec guard — exactly the surface the shipped 4:4:4 bug (`hevcConfig` stamped onto an AV1 config) lived on. Plain union-arm *writes* stay bare: the `.25` gate corrected me — they're safe by language rule (the hazard is the mismatched read).
## The grep gates (WP2c part 2) — `2bfd1cd2`, blocking in ci.yml
`scripts/ci/check-unsafe-hygiene.sh`, three classes no lint covers:
- **A. `unsafe fn` markers carrying no contract** (the `db659809` class). Waivable for contract-deferring fns (`set_len` shape) with `// unsafe-fn-no-op-ok: <reason>`; fenced files and signature-mandated `unsafe extern "ABI" fn` callbacks skipped structurally.
- **B. `unwrap`/`expect`/`panic!` in `extern "C"`/`"system"` bodies** — an abort since Rust 1.81 (the `8b98d0b3` class). `catch_unwind` bodies exempt.
- **C. Process-global safe APIs** (`env::set_var`, `sigaction`, …) — the `972af299` class, invisible to the unsafe census. Per-file count ratchet; any increase or new file fails.
Making gate B clean surfaced **14 real instances of exactly its class** — `.lock().unwrap()` in unguarded extern fns, where a poisoned mutex aborts the embedding process: six `punktfunk-core` `abi.rs` entry points, seven Android JNI entry points, and the Windows client's deeplink `wnd_proc`. All fixed with poison-recovering locks + `Option::insert` for the set-then-unwrap shape. Gate A's six findings were genuine contract-deferring fns — waived with reasons.
Gate-of-the-gate: all three shown to **fail on deliberately planted instances** (and re-shown after the mawk-portability rewrite — the awk originally used a gawk-only empty-separator `split`, which Debian's mawk would have made silently vacuous), and to run clean, before the ci.yml step made them blocking.
## Verification
- **`.25`** — `cargo clippy --workspace --all-targets --locked -- -D warnings` exit 0 on the final tree (GTK client excluded: box lacks GTK dev packages, real CI installs them), plus the ci.yml feature-gated encode leg: clippy exit 0, **120 tests pass** (covers nvenc_core under its new lint).
- **`.133`** — the full lint suite, extract-first with sentinels + `cargo clean` so a stale upload can't pass: **all 12 steps exit 0** — host/encode (`nvenc,amf-qsv,qsv`), capture, vdisplay, tray, the Windows client, pf-vkhdr-layer fmt+clippy, and the drivers workspace clippy **including wdk-probe under the real WDK** + drivers fmt.
- punktfunk-core's 203 lib tests pass locally; native macOS clippy clean for everything that compiles there (three pre-existing mac-native failures reproduce on the clean tree).
pf-vkhdr-layer — the sharpest gap: an implicit layer injected into every
Vulkan game process, 32 unsafe usages, zero SAFETY comments, own workspace so
no lint table reached it, and an explicit missing_safety_doc allow. Now: a
[lints] table (unsafe_op_in_unsafe_fn + clippy::undocumented_unsafe_blocks,
both deny), the allow removed, every unsafe operation in an explicit block
with a real proof (loader layer protocol / Vulkan valid-usage), # Safety docs
on the contract-carrying fns, const layout asserts for the SurfaceFormat2Raw
mirror, the five helpers with no caller-facing contract demoted to safe fns,
and the two redundant `unsafe impl Send` deleted (fn pointers and vk handles
are Send intrinsically — the type-check proves it).
wdk-probe — 21 unsafe blocks, 12 proofs: the 9 missing SAFETY comments are
written (the iddcx_rt.rs DDI slot-dispatch ones are about table population
and PFN/index pairing, not pattern fill), the sibling denies added at the
crate root, missing_safety_doc allow dropped, # Safety on DriverEntry, and
the crate joins windows-drivers.yml's clippy list — it was the only driver
crate not in it.
pf-clipboard — the undocumented_unsafe_blocks deny moves from host/windows.rs
to the crate root so host/wayland.rs (4 blocks), host/mutter.rs (2) and any
future backend under host/ are covered on creation. All existing blocks
already carry proofs; free today, structural tomorrow.
Verified here: pf-vkhdr-layer cargo fmt --check + clippy --release
-D warnings at x86_64-pc-windows-msvc. wdk-probe and pf-clipboard compile
checks need the WDK/Linux boxes and ride the .133/.25 gate.
undocumented_unsafe_blocks joins unsafe_op_in_unsafe_fn in
[workspace.lints], and the ~100 scattered per-file #![deny(...)] attributes
(85 files) are deleted — a new crate, or a new module in an old one, is now
covered on creation rather than on remembering. The per-file form is how
pf-vkhdr-layer, wdk-probe and half of pf-clipboard stayed uncovered.
There are THREE workspaces, so the claim is made three times: the main
Cargo.toml, packaging/windows/drivers (workspace table + [lints]
workspace = true in all seven members), and packaging/windows/pf-vkhdr-layer
(its [lints] table, previous commit). pf-update now opts into workspace
lints; the two vendored member snapshots (cros-codecs, usbip-sim) stay out
deliberately and now both say so.
Newly-covered fallout was two link-sanity tests (pyrowave-sys, libvpl-sys)
— proofs written. Stale prose that claimed the workspace held
unsafe_op_in_unsafe_fn at "warn" (it has been deny) or pointed at the
deleted attributes is corrected.
nvenc_core.rs is carved OUT of the unsafe_op_in_unsafe_fn fence: its
exemption rationale ("raw entry-table calls almost line for line") was
false — the file makes zero FFI calls. Its unsafe surface is C-union writes
whose soundness hangs on which codec arm is active, and its own 4:4:4 note
records the shipped bug (hevcConfig bytes stamped onto an AV1 config) that
per-operation blocks make visible. It now runs the strictest discipline in
the crate: clippy::multiple_unsafe_ops_per_block at deny, one union access
per block, each naming its codec guard.
Verified here: cargo fmt clean in all three workspaces; native clippy
-D warnings clean for everything that compiles on macOS (the three
pre-existing mac-native failures — pf-client-core wol.rs, pf-encode
dead-code/closure-call, probe mic_burst — reproduce on the clean tree).
Linux/Windows legs ride the .25/.133 gate.
scripts/ci/check-unsafe-hygiene.sh — textual gates for three classes no lint
covers:
A. unsafe fn markers carrying no contract. unsafe_op_in_unsafe_fn forces real
ops into blocks, so an unsafe fn with no `unsafe` in its body is a marker
with no contract (db659809 found two by hand). Contract-deferring fns
(Vec::set_len shape) waive with `// unsafe-fn-no-op-ok: <reason>`; fenced
files and `unsafe extern "ABI" fn` (signature-mandated markers) are
skipped structurally.
B. unwrap/expect/panic! inside extern "C"/"system" bodies — an abort since
Rust 1.81, not linted, not fuzzable (8b98d0b3). catch_unwind bodies are
exempt; `// panic-in-extern-ok: <reason>` waives a deliberate abort.
C. Safe-but-process-global APIs (env::set_var/remove_var, sigaction,
setlocale, set_current_dir) — the 972af299 environ race lived in a file
with zero occurrences of the word `unsafe`. Per-file count ratchet with
the baseline in the script; any increase or new file fails.
Making gate B clean on main surfaced 14 real instances of exactly its class —
`.lock().unwrap()` in unguarded extern fns, where a poisoned mutex aborts the
embedding process: six punktfunk-core abi.rs entry points (poll_frame,
next_au, next_audio, next_audio_pcm, next_cursor_shape, next_clipboard),
seven Android JNI entry points, and the Windows client's deeplink wnd_proc.
All fixed with poison-recovering locks (the slots are last-value caches,
valid whatever a poisoned writer left) and Option::insert for the
set-then-unwrap shape; punktfunk-core's 203 lib tests pass. Gate A's
findings were six genuine contract-deferring fns — waived with reasons, not
fixed, because the markers are correct.
Gate-of-the-gate: all three shown to FAIL on deliberately planted instances
(marker fn, panicking extern callback, env::set_var in an unlisted file) and
to run clean on the tree, before the ci.yml step made them blocking.
Linux fallout from the hoist the mac could not see: bindgen emits unsafe
blocks (layout tests/accessors) into OUT_DIR, where nobody hand-writes
SAFETY proofs — pyrowave-sys failed clippy on .25 with 17 of them, and
libvpl-sys would do the same on the Windows leg. Both crates are
bindings-only by charter (the safe wrapper lives with the consumer), so the
allow is crate-wide with the rationale at the crate root; the hand-written
link-sanity tests keep their proofs by convention.
The .25 gate corrected the carve-out: rustc flags `unsafe { u.arm.field = x }`
as unused_unsafe — plain assignment through a union projection is safe
(writing an arm cannot itself be UB; the hazard is the mismatched READ).
The 11 plain writes go back to bare statements under their codec matches.
What stays in per-op unsafe blocks with arm-guard proofs is the real unsafe
surface: union reads, borrows, and the bindgen bitfield-setter calls — which
is exactly the surface the shipped 4:4:4 bug lived on (set_chromaFormatIDC
stamped under a wrong codec).
The tray leg builds punktfunk-core with default-features off, where
lock_recover's only callers (the quic-gated punktfunk_connection_* entry
points) do not exist — dead code under -D warnings. The helper takes the
same feature gate.
In pf-vkhdr-layer, rustfmt had reflowed destroy_surface's lookup into a
multiline closure, leaving the SAFETY comment outside the closure that
contains its unsafe block — the box's clippy rightly stopped accepting the
adjacency. The comment moves inside, directly above the block.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Finishes the rust-safety programme's §4 WP2 from
design/rust-safety-lint-ratchets-handoff.md. Moves the primary unsafe metric by ~zero, by design — everything here is a permanent structural control that stops new undisciplined code accruing.The three crate-level gaps (WP2b) —
23fa03b0missing_safety_docallow. Now: a[lints]table (unsafe_op_in_unsafe_fn+clippy::undocumented_unsafe_blocks, both deny), every unsafe operation in an explicit block with a written proof (loader layer protocol / Vulkan valid-usage / the two hand-computed struct offsets),# Safetydocs on the contract-carrying fns, const layout asserts on theSurfaceFormat2Rawmirror, five contract-free helpers demoted to safe fns, and both redundantunsafe impl Senddeleted (fn pointers areSendintrinsically — the type-check proves it).iddcx_rt.rsDDI slot-dispatch ones argue table population and PFN/index pairing, not pattern fill), sibling denies added, and the crate joinswindows-drivers.yml's clippy list — it was the only driver crate not in it.host/windows.rsto the crate root, sowayland.rs,mutter.rs, and any future backend underhost/are covered on creation. Free today (all six blocks already carried proofs).The hoist (WP2c part 1) —
dfebb9df+5f097d53+abec2a14undocumented_unsafe_blocks = "deny"joinsunsafe_op_in_unsafe_fnin[workspace.lints], and ~100 scattered per-file#![deny(...)]attributes across 85 files are deleted. There are three workspaces, so the claim is made three times (main,packaging/windows/drivers+[lints] workspace = truein all seven members,packaging/windows/pf-vkhdr-layer).pf-updatenow inherits workspace lints; the vendored member snapshots (cros-codecs, usbip-sim) stay out deliberately and both now say so. Newly-covered fallout: two link-sanity tests (proofs written) and the two bindings-only sys crates (bindgen output in OUT_DIR can't carry hand-written proofs — crate-wide allow with rationale).nvenc_core.rs is carved out of the
unsafe_op_in_unsafe_fnfence: its exemption rationale ("raw entry-table calls almost line for line") was false — the file makes zero FFI calls. It now runs the strictest discipline in the crate:clippy::multiple_unsafe_ops_per_blockat deny, every union read/borrow/bitfield-setter call in its own block naming its codec guard — exactly the surface the shipped 4:4:4 bug (hevcConfigstamped onto an AV1 config) lived on. Plain union-arm writes stay bare: the.25gate corrected me — they're safe by language rule (the hazard is the mismatched read).The grep gates (WP2c part 2) —
2bfd1cd2, blocking in ci.ymlscripts/ci/check-unsafe-hygiene.sh, three classes no lint covers:unsafe fnmarkers carrying no contract (thedb659809class). Waivable for contract-deferring fns (set_lenshape) with// unsafe-fn-no-op-ok: <reason>; fenced files and signature-mandatedunsafe extern "ABI" fncallbacks skipped structurally.unwrap/expect/panic!inextern "C"/"system"bodies — an abort since Rust 1.81 (the8b98d0b3class).catch_unwindbodies exempt.env::set_var,sigaction, …) — the972af299class, invisible to the unsafe census. Per-file count ratchet; any increase or new file fails.Making gate B clean surfaced 14 real instances of exactly its class —
.lock().unwrap()in unguarded extern fns, where a poisoned mutex aborts the embedding process: sixpunktfunk-coreabi.rsentry points, seven Android JNI entry points, and the Windows client's deeplinkwnd_proc. All fixed with poison-recovering locks +Option::insertfor the set-then-unwrap shape. Gate A's six findings were genuine contract-deferring fns — waived with reasons.Gate-of-the-gate: all three shown to fail on deliberately planted instances (and re-shown after the mawk-portability rewrite — the awk originally used a gawk-only empty-separator
split, which Debian's mawk would have made silently vacuous), and to run clean, before the ci.yml step made them blocking.Verification
.25—cargo clippy --workspace --all-targets --locked -- -D warningsexit 0 on the final tree (GTK client excluded: box lacks GTK dev packages, real CI installs them), plus the ci.yml feature-gated encode leg: clippy exit 0, 120 tests pass (covers nvenc_core under its new lint)..133— the full lint suite, extract-first with sentinels +cargo cleanso a stale upload can't pass: all 12 steps exit 0 — host/encode (nvenc,amf-qsv,qsv), capture, vdisplay, tray, the Windows client, pf-vkhdr-layer fmt+clippy, and the drivers workspace clippy including wdk-probe under the real WDK + drivers fmt.undocumented_unsafe_blocks joins unsafe_op_in_unsafe_fn in [workspace.lints], and the ~100 scattered per-file #![deny(...)] attributes (85 files) are deleted — a new crate, or a new module in an old one, is now covered on creation rather than on remembering. The per-file form is how pf-vkhdr-layer, wdk-probe and half of pf-clipboard stayed uncovered. There are THREE workspaces, so the claim is made three times: the main Cargo.toml, packaging/windows/drivers (workspace table + [lints] workspace = true in all seven members), and packaging/windows/pf-vkhdr-layer (its [lints] table, previous commit). pf-update now opts into workspace lints; the two vendored member snapshots (cros-codecs, usbip-sim) stay out deliberately and now both say so. Newly-covered fallout was two link-sanity tests (pyrowave-sys, libvpl-sys) — proofs written. Stale prose that claimed the workspace held unsafe_op_in_unsafe_fn at "warn" (it has been deny) or pointed at the deleted attributes is corrected. nvenc_core.rs is carved OUT of the unsafe_op_in_unsafe_fn fence: its exemption rationale ("raw entry-table calls almost line for line") was false — the file makes zero FFI calls. Its unsafe surface is C-union writes whose soundness hangs on which codec arm is active, and its own 4:4:4 note records the shipped bug (hevcConfig bytes stamped onto an AV1 config) that per-operation blocks make visible. It now runs the strictest discipline in the crate: clippy::multiple_unsafe_ops_per_block at deny, one union access per block, each naming its codec guard. Verified here: cargo fmt clean in all three workspaces; native clippy -D warnings clean for everything that compiles on macOS (the three pre-existing mac-native failures — pf-client-core wol.rs, pf-encode dead-code/closure-call, probe mic_burst — reproduce on the clean tree). Linux/Windows legs ride the .25/.133 gate.The .25 gate corrected the carve-out: rustc flags `unsafe { u.arm.field = x }` as unused_unsafe — plain assignment through a union projection is safe (writing an arm cannot itself be UB; the hazard is the mismatched READ). The 11 plain writes go back to bare statements under their codec matches. What stays in per-op unsafe blocks with arm-guard proofs is the real unsafe surface: union reads, borrows, and the bindgen bitfield-setter calls — which is exactly the surface the shipped 4:4:4 bug lived on (set_chromaFormatIDC stamped under a wrong codec).