Skip to content

audit cleanup + DXGI probe for Windows-arm winget#38

Merged
packetThrower merged 28 commits into
mainfrom
chore/audit-2026-05-22
May 24, 2026
Merged

audit cleanup + DXGI probe for Windows-arm winget#38
packetThrower merged 28 commits into
mainfrom
chore/audit-2026-05-22

Conversation

@packetThrower
Copy link
Copy Markdown
Owner

Summary

  • 23-commit codebase audit pass: split app_view.rs (7,235 → 4,127 LOC) and settings_view.rs (3,826 → 2,733 LOC) into per-concern sibling modules; narrowed module-wide allow(dead_code); deleted Tauri-era residue (events.rs, state.rs); applied cargo-fmt baseline + added CI fmt-check + cargo-deny supply-chain audit + scripts/* compile-verification step.
  • Direct3D adapter probe in main.rs::dxgi_probe runs before any gpui state exists. On failure pops the same Windows error dialog flavour and exits 0 — bypasses the cleanup-time AsyncApp::update_entity RefCell panic that kept arm64 out of v0.12.4's winget submission (microsoft/winget-pkgs#377461).
  • workflow_dispatch trigger on release.yml for ad-hoc arm64 builds without tagging. Cherry-picked separately to main earlier so this branch can be dispatched while in PR.

Test plan

  • cargo clippy --all-targets -- -D warnings clean on every commit (local macOS)
  • cargo test — 63 passing on every commit, no test count change
  • cargo deny check — advisories / bans / licenses / sources all ok
  • Workflow dispatch run 26339513392 green on all 6 CI matrix entries + 5 build jobs
  • arm64 Baudrun.exe launches normally on Windows 11 arm in UTM (happy path)
  • DXGI probe doesn't false-positive on degraded GPU states (verified via Device Manager → disable VirtIO GPU → Microsoft Basic Display Driver fallback satisfies the probe → Baudrun still launches)
  • DXGI probe failure path actually exits 0 in the validator's headless arm64 sandbox — only reproducible in the real validator env; resolved when the v0.12.5 winget submission runs

Each commit is independently buildable + tested; bisecting remains useful across the branch.

Out of scope (follow-ups)

  • arm64 not yet re-added to packaging/windows/winget/packetThrower.Baudrun.installer.yaml.template — happens after this lands, v0.12.5 is cut, and the arm64 .msi ships. Full sequence captured in TODO.md's new "Re-include arm64 in the winget submission" entry.
  • data::usbserial::cp210x libusb-direct backend still not wired into serial_io::open as a fallback — chore/audit flagged this via a TODO.md entry after the user surfaced the Siemens RuggedCom RST2228 use case. Separate work item, not part of this branch.

🤖 Generated with Claude Code

packetThrower and others added 28 commits May 22, 2026 20:32
Pure formatting pass over the src/ tree to establish a rustfmt-
clean baseline before adding `cargo fmt --check` as a CI gate
in the next commit. No behaviour or logic changes — `cargo
clippy --all-targets -- -D warnings` and `cargo test` both pass
unchanged (63 tests).

The drift accumulated organically over Phase 2 onwards; locking
the baseline now keeps subsequent module splits (app_view,
settings_view) on the rustfmt grid so their diffs read as pure
movement rather than mixed move+reflow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Locks in the rustfmt baseline established by the previous commit
so future drift surfaces at PR time. The check runs once on the
ubuntu-latest matrix entry (fmt is platform-independent) and
slots between the cargo cache and the platform deps install so
a fmt regression fast-fails in seconds rather than after the
apt-get pass.

rustfmt joins the existing clippy component on the rust-toolchain
step — both are cached via Swatinem/rust-cache so the marginal
cost is the one-time component download on cache miss.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
"Platform support — early days" framed the gpui rewrite as fresh,
which fit v0.9.7-alpha but not v0.12 with four months of arm64
winget work, Scoop submissions, and shipped Windows boot fixes
behind it. The new wording mirrors TODO.md's canonical statement
("macOS is the primary dev / test target. Windows + Linux are
kept in mind in code, verified periodically — Linux less often
since gpui's Linux backend is the least-mature of the three.")
so the two stay in lockstep.

What changes for users reading a release page:

  * Drop "early days" — the gpui line is past that bar.
  * Drop "not yet routinely tested" for Windows — Windows builds
    do get periodic real-hardware testing (the VCRedist regression
    in 0.12.0, the boot fast-fail in 0.12.3, the USB-serial driver
    detection work in the 0.11 line all came from real-hardware
    sessions).
  * Keep Linux honest — it's still the least-exercised of the
    three, which TODO.md already calls out.

The disclaimer-block-drops-entirely TODO stays in the workflow
comment for the day all three platforms hit the macOS bar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`bundled_packs` used to `unwrap_or_else(panic!)` on any serde
parse failure, so a single malformed JSON in the binary would
abort boot before AppView ever rendered. The well-formedness
invariant is already gated by the `bundled_packs_parse` unit
test (and the project keeps clippy clean as CI policy), so the
panic site existed for a class of failures that's caught by CI
in practice — but absorbed by the user as "Baudrun won't launch"
in the (vanishingly rare) cases where it does reach prod.

Replace the panic with `log::error!` + skip-this-pack. The rest
of the bundled set continues to load; the user sees their
highlight options narrowed by one pack rather than facing an
unlaunchable app. `baudrun-default` keeps its hard-fail
invariant because `default_user_pack`'s `.expect` downstream
still hard-stops on it (the user-pack seed depends on it being
present), and that's the load-bearing pack we genuinely cannot
recover from losing.

No new test: the existing `bundled_packs_parse` already
exercises this function fully and asserts the post-condition
we care about (all bundled packs present and well-formed). The
new path is defense-in-depth for a scenario the test suite
catches before ship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `#![allow(dead_code, unused_imports)]` at the top of
`data/mod.rs` was a Phase-1 holdover from when the data layer
was ported from `src-tauri/src/` but not yet wired into any UI.
Phase 2 onwards consumed most of these modules — but the
blanket allow stayed put, masking new orphans accumulated during
the gpui rewrite. Narrowing it surfaces accidental dead code in
future PRs while preserving the intentional-orphan code we want
to keep buildable.

Module-status pass:

  * File-level `#![allow(dead_code)]` on the modules that are
    fully orphaned but worth keeping compiled as reference:
    `serial/session.rs`, `serial/direct.rs`, `serial/usb_darwin.rs`,
    `usbserial/mod.rs`, `usbserial/cp210x.rs`. These are the
    Tauri-era libusb-direct serial path; the gpui code goes
    `serialport`-only via `src/serial_io.rs`.

  * File-level `#![allow(dead_code)]` + "candidate for full
    deletion" note on Tauri-pure residue: `events.rs` (event-bus
    constants) and `state.rs` (the old `AppState`/`SessionHandle`
    keyed by Tauri window label). gpui's Entity/Global system +
    `SettingsBus` replace both wholesale. Per the audit's
    "flag, don't delete pre-existing dead code" rule I haven't
    removed these — surfacing them here so a follow-up can.

  * Item-level `#[allow(dead_code)]` / `#[allow(unused_imports)]`
    on the singletons in otherwise-live modules:
    `serial/mod.rs` (re-exports + `detect_missing_drivers`),
    `serial/chipsets.rs::driver_url_for_vid`,
    `highlight.rs::update_user_pack`,
    `skins.rs::resolve`, `themes/mod.rs::resolve`. These ride in
    actively-used modules so the file-level allow would over-
    suppress — narrowing to the specific items keeps the rest of
    each module honest.

  * `data/mod.rs` itself: blanket allow removed, doc comment
    refreshed to enumerate the status of each submodule so a
    future reader doesn't have to grep the whole tree.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four checks scoped to what's actually load-bearing for a binary
crate that pulls in a large Zed-git tree:

  * advisories — RUSTSEC vulnerabilities + unmaintained warnings.
    Four upstream-unmaintained transitive deps are listed in
    `ignore =` with the dep chain + reason for each (paste,
    rustls-pemfile, async-std, instant). All four trace into
    gpui / gpui-component / image and can't be fixed without
    upstream bumps; the ignore list documents what to revisit
    when those land.
  * licenses — explicit allow-list of GPL-3-compatible permissive
    licenses (the project itself is GPL-3-or-later, so deps must
    be compatible). Two per-crate exceptions for bzip2-1.0.6 and
    NCSA; one clarify entry for `unescaper`'s deprecated
    `GPL-3.0/MIT` SPDX form. Each one carries an explanation
    rather than a bare crate-name allowance.
  * bans — `multiple-versions = "warn"` because the Zed-git tree
    duplicates windows-sys / bitflags / fastrand etc. across
    versions and "deny" would block every PR. `wildcards = "warn"`
    for the same reason: our four `git = "..."` deps register as
    wildcards (no version constraint) and the Cargo.toml comment
    on the gpui dep documents why we deliberately don't pin a rev.
  * sources — `unknown-registry = "deny"` and `unknown-git = "deny"`
    with `[sources.allow-org]` scoped to `zed-industries` and
    `longbridge`. Org-level allow (not per-URL) because Zed pulls
    in transitive deps from at least six sibling repos under
    `zed-industries/*` and pinning the list per-URL would break
    on every Zed bump.

The matching CI step lives on the ubuntu-latest matrix entry
only — cargo-deny reads Cargo.lock and is platform-independent,
so running it six times across the matrix would waste runner
minutes. taiki-e/install-action fetches a prebuilt binary
rather than building from source, ~3 min savings on cold runs.

`license = "GPL-3.0-or-later"` added to `[package]` so cargo-
deny's no-license-field warning doesn't fire on our own crate.
Informational-only since `publish = false`.

Verified: `cargo deny check` reports `advisories ok, bans ok,
licenses ok, sources ok` on a clean cache.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-split scaffolding. `app_view.rs` (7,235 lines) becomes
`app_view/mod.rs` so subsequent commits can lift leaf concerns
(session/window scaffolding, opts, buttons, chrome, editor,
transfer) into sibling files without changing call sites —
`crate::app_view::Foo` continues to resolve the same way.

Pure rename: zero content change, identical compile output,
`cargo clippy --all-targets -- -D warnings` and `cargo test`
unchanged (63 tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lifts the small leaf concerns out of mod.rs:

  * `SessionBundle` — the moved-between-windows live-session
    container.
  * `WindowInit` — the three-variant discriminator passed to
    `open_app_window` (Fresh / WithSession / FreshAutoConnect).
  * `geometry_to_bounds` / `bounds_to_geometry` — the
    `WindowGeometry` ↔ `gpui::Bounds<Pixels>` helpers used by
    `open_app_window`'s saved-bounds restore + the
    `on_window_should_close` snapshot path.

Behaviour-preserving. `SessionBundle`'s fields stay package-
private to the `app_view` module via `pub(super)` so the parent's
`extract_session` / `install_session` methods continue to
construct and destructure it directly — the bundle is
intentionally a thin movable container, not a closed type with
constructors.

While I was here: reattached the orphan doc comment for
`open_app_window`, which had drifted into the gap between
`WindowInit` and the geometry helpers when those helpers were
inserted in an earlier change. It now sits where it belongs.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lifts the window-construction entry point out of mod.rs into
`app_view::window`, re-exported as `app_view::open_app_window`
so main.rs's `use app_view::{open_app_window, AppView,
WindowInit};` continues to resolve without change.

Moves: `pub fn open_app_window` (~135 lines) + the
`TRAFFIC_LIGHT_POSITION_PX` const that backs its
`traffic_light_position` titlebar option.

The const stays shared with `AppView::open_settings_window` in
mod.rs (the Settings window uses the same traffic-light
position so the two windows feel uniform). Exposed via
`pub(super)` and re-imported into mod.rs by name.

`open_app_window` calls the still-private `AppView::connect_to`
and reads the still-private `AppView::profile_store` field from
its sibling module — that works without visibility widening
because Rust's privacy rule lets descendant modules see the
parent's private items (window.rs is a descendant of the
app_view module that defines AppView).

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`line_pill`, `pill_button`, `primary_button` move into a new
`app_view::buttons` child module. All three are pure-style
helpers (return a bare `gpui::Div` with no event handlers) used
across the session header and the profile form, with no
external callers outside `app_view`.

Visibility: `pub(super)` on each so mod.rs imports them by name
into its own namespace. `STATUS_DOT_PX` (consumed by `line_pill`
for the status dot's diameter) stays private in mod.rs and
reaches buttons.rs via Rust's descendants-see-parent-privates
rule, same as the `connect_to` / `profile_store` access from
window.rs.

While here: reattached `pill_button`'s doc comment, which had
slipped one slot up the file so it was sitting on top of
`line_pill` instead. The fn definitions kept the wrong layout
because both helpers have similar enough shape that the
mis-doc didn't surface during reads.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`struct Opt`, its `impl Opt` / `impl SelectItem`, the
`make_select` / `read_select` wrappers, and every per-field
option-list builder (baud, data_bits, parity, stop_bits,
flow_control, line_ending, line_policy, backspace, port) move
into a new `app_view::opts` child module. About 200 lines, all
of which were a coherent profile-form helper layer.

`Opt` keeps its fields private; only the `pub(super) fn new`
constructor + the `SelectItem` impl reach across the module
boundary. Same descendants-see-parent rule used for the earlier
splits — opts.rs can call back into `super::AppView` for the
`Context<AppView>` it needs in `make_select` / `read_select`.

`port_opts` rides along because it returns the same `Vec<Opt>`
shape and the editor composes it alongside the static lists,
even though its data comes from `serial::ports::list_ports()`
rather than a hardcoded table. The `pub use ...::ports` in
mod.rs's import block drops out as a side effect — its only
remaining user is now in opts.rs.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lifts the 11 window-chrome / overlay helper functions out of
mod.rs into a new `app_view::chrome` child module:

  * `profile_context_menu_overlay` + `profile_menu_item` — the
    sidebar right-click popup and its single row primitive
  * `suspended_banner` + `suspended_pane` — the two visual
    treatments for a session in `Suspend` mode
  * `about_dialog_body` — content for the About dialog
  * `friendly_open_error` — serial-open error string formatter
    (the only non-rendering helper in the file; lives here
    because every caller is a render-time error path)
  * `welcome_pane` — the empty-state shown at boot with no
    connected profile
  * `session_header` + `status_bar` + `session_overflow_button` —
    the top toolbar, bottom status row, and `⋯` overflow menu
  * `sidebar_header` + `sidebar_icon_strip` — the two layouts
    for the left sidebar (expanded vs. collapsed)

All eleven are `pub(super)` so mod.rs imports them by name.
Internal cross-references (e.g. `session_overflow_button` calling
`profile_menu_item`) stay private. The trailing comment block
about chrome consts having migrated to `SkinTokens` rides along
with the chrome code so the historical note keeps its proximity
to the helpers it describes.

While here: rolled `session_overflow_button` (which had stayed
in mod.rs after the earlier Phase D split) into chrome.rs since
it's an inline child of `session_header` and shares the same
popup-paint pattern as `profile_context_menu_overlay`. Cleans up
the `use buttons::{line_pill, ...}` line on mod.rs too —
`line_pill` was only used by `session_header`, which now lives
in chrome.rs.

mod.rs drops by ~990 lines (6,643 → 5,651). chrome.rs lands at
1,032 lines — large but cohesively scoped to "render-time
chrome subtree producers."

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lifts the profile-editor form rendering + state-bridging out of
mod.rs into a new `app_view::editor` child module. About 1,400
lines covering:

  * `build_editor` / `apply_editor_to_profile` — the bidirectional
    bridge between a `Profile` and the live form widget state.
  * `editor_fields_match` — dirty-check predicate that drives the
    Save button's brightness.
  * `EditorRender` + its `from(&Editor, &Context)` constructor —
    the cloned-out widget handles a render pass needs, so the
    render code can hand `cx: &mut Context<AppView>` to form
    helpers without keeping `&self.editor` borrowed alongside.
  * `form_pane` — the public entry; called from `Render for AppView`.
  * `form_header`, `form_body`, `form_tab_nav`, `section_card`,
    `section_card_with_desc`, `labeled`, `bool_field`,
    `bool_field_hinted`, `connection_card`, `terminal_card`,
    `highlighting_pane`, `advanced_pane`, `theme_card`,
    `control_lines_card`, `output_card`, `paste_safety_card` —
    the internal helpers that compose the form's visual tree.
  * `detect_missing_drivers` + `driver_banner_row` — the
    unenrolled-USB-driver warning shown above the Serial Port
    field; only the form renders this so it lives here.

Visibility plan: `pub(super)` on the four items mod.rs actually
references (`build_editor`, `apply_editor_to_profile`, `form_pane`,
`struct EditorRender` + `EditorRender::from`). The rest stay
private — `form_header` / `form_body` / etc. are only ever called
from within editor.rs.

`struct Editor` + `enum EditorTab` stay in mod.rs because the
parent's methods on `AppView` (set_editor_tab, save_editor,
toggle_local_echo, …) do direct field access on Editor, and the
descendants-see-parent-private rule means editor.rs can still
read those fields without per-field `pub(super)` widening. The
split is along "form rendering & state-bridging logic" lines
rather than "Editor data type and friends."

mod.rs drops by ~1,395 lines (5,651 → 4,256). editor.rs lands at
1,441 lines — large, but every item is part of the editor form
pipeline.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lifts the Send-File-specific UI primitives out of mod.rs:

  * `YMODEM_PROTOCOL_ID` + `transfer_protocol_opts` — the
    Select widget's default pick + option list.
  * `send_file_field_label`, `send_file_path_pill`,
    `send_file_choose_button`, `send_file_secondary_button`,
    `send_file_primary_button` — dialog-specific pill/button
    helpers. Kept separate from the generic `buttons.rs`
    primitives because they have distinct sizing + spacing
    (Send File uses a wider px_4 / py(6.0) button vs the
    generic px_3 / py_1).

Module name is `transfer_ui` rather than `transfer` to avoid
shadowing `crate::data::transfer`, which mod.rs's transfer
state-machine driving (`send_xmodem`, `send_ymodem`, etc.)
imports as `transfer::`. The `_ui` suffix accurately names the
content (Send-File-dialog UI helpers) rather than the broader
transfer concept.

The transfer **types** (`TransferIo`, `TransferState`,
`TransferResult`, `SendHexState`, `SendFileState`) stay in
mod.rs. Their fields are accessed across ~20 AppView methods
that drive the transfer state machine; moving them would force
13+ `pub(super)` field-visibility widenings for no functional
gain. The split here is "render helpers only" — same rationale
as keeping `Editor` in mod.rs while moving the form rendering.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-split scaffolding. `settings_view.rs` (3,826 lines) becomes
`settings_view/mod.rs` so subsequent commits can lift leaf
concerns (shortcuts marshalling, theme preview, generic
controls) into sibling files without changing call sites —
`crate::settings_view::SettingsView` /
`settings_view::SHORTCUT_ACTIONS` /
`settings_view::effective_shortcut` /
`settings_view::spec_to_gpui_binding` all continue to resolve
the same way.

Pure rename: zero content change, identical compile output,
`cargo clippy --all-targets -- -D warnings` and `cargo test`
unchanged (63 tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…g into shortcuts.rs

Lifts the entire "shortcuts data + keystroke spec marshalling"
section out of mod.rs into `settings_view::shortcuts`:

  * Public surface (re-exported as `settings_view::*`):
    - `SHORTCUT_ACTIONS` (canonical id list, display order)
    - `effective_shortcut(action, overrides)` (resolves a row's
      live binding, honouring overrides over per-OS defaults)
    - `spec_to_gpui_binding(spec)` (Tauri-style spec →
      gpui keybinding string for `cx.bind_keys`)
  * `pub(super)` helpers used by `SettingsView` itself:
    - `shortcut_label` (display label per action id)
    - `format_spec(&Keystroke)` (Tauri-style spec for persistence)
    - `parse_spec(spec)` (reverse, for rendering the live pill)
    - `any_modifier(&Modifiers)` (recording-state Escape gating)
  * Module-private:
    - `default_for_action` (per-OS — two cfg-gated copies)
    - `canonical_key_for_storage` / `canonical_key_for_display`
      (normalisation between gpui key names and Tauri storage)

Visibility plan keeps the original `pub(crate)` for the three
items main.rs consumes via `settings_view::*`, narrows the four
internal helpers to `pub(super)`, and leaves the helpers used
only inside shortcuts.rs unannotated.

mod.rs drops by ~315 lines (3,763 → 3,452). The
`std::collections::HashMap` + `gpui::{Keystroke, Modifiers}`
imports come out of mod.rs along with the moved code — no
remaining caller named those types.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ew.rs

Lifts the theme rendering helpers out of mod.rs into a new
`settings_view::theme_preview` child module:

  * `pub(super)` entry points:
    - `theme_swatches(&Theme)` — compact 8-color strip rendered
      at the left of each installed-themes row.
    - `theme_preview_block(&Theme)` — full-fidelity preview
      dialog body, sample lines + paired fg/bg blocks.
  * Module-private helpers:
    - `preview_sample_lines()` — the canned sample-output rows
      the preview block renders against each theme's palette.
    - `parse_theme_color(&str)` — `#RRGGBB` / `#RGB` / `#RRGGBBAA`
      → `0xRRGGBBAA` u32 used by gpui's `rgba`.

About 235 lines of self-contained colour-rendering code that
has no callers outside `settings_view`. The `SharedString`
import comes along on theme_preview.rs (used inline by
`theme_preview_block`); the `gpui::SharedString` line stays in
mod.rs because settings_view's keystroke-capture path still
needs it.

mod.rs drops by ~235 lines (3,452 → 3,215).

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…chrome.rs

Lifts the structural chrome + reusable form controls out of
mod.rs into a new `settings_view::chrome` child module. About
475 lines covering 11 `pub(super)` helpers:

  * Window structure: `window_header`, `rail`, `scrollable_pane`,
    `section_card_with_desc`, `bool_field`.
  * Generic affordances: `dismiss_notification_after`,
    `encode_file_path`, `resolve_config_dir_display`,
    `import_button`, `trash_button`, `make_select`.

Two pre-existing doc-comment layout bugs surfaced and got
fixed along the way:

  * `dismiss_notification_after`'s doc was duplicated inline
    (6 lines of "Schedule a Notification…" repeated verbatim,
    pre-existing in mod.rs at HEAD). De-duplicated in the move,
    single clean copy now lives above the fn in chrome.rs.

  * `import_button`'s doc had drifted up into the gap between
    `bool_field` and the `SECTION_KEYWORDS` const in HEAD, so
    `import_button` itself rendered undocumented. Reattached
    to the actual fn in chrome.rs.

The taxonomy consts (`SECTION_KEYWORDS`, `TAB_SECTIONS`) stay
in mod.rs because they're data tables consumed by
`SettingsView`'s filter logic rather than chrome primitives —
moving them would force `pub(super)` widenings on
`SettingsTab` enum variants for no functional gain.

mod.rs drops by ~480 lines (3,215 → 2,734).

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The winget validator's headless arm64 sandbox can't initialize a
Direct3D device, so gpui's renderer init returns
`DXGI_ERROR_NOT_CURRENTLY_AVAILABLE` (`0x887A0022`). That used to
fast-fail under `panic = "abort"` (caught in v0.12.2 → fixed in
535b7ec by handling the Err) but even after the v0.12.3 + v0.12.4
fixes that landed the dialog + skipped `cx.quit()`, a deeper
`AsyncApp::update_entity` panic still fires during cleanup of
state set up before the failed window open
(`gpui_component::init`, the settings-bus subscribe). That kept
arm64 out of v0.12.4's winget submission
(microsoft/winget-pkgs#377461).

Path B from the audit's winget triage: probe D3D11 before any
gpui state exists. Inline FFI on `D3D11CreateDevice` (d3d11.dll),
matching the shape of `show_window_open_error_dialog`'s
`MessageBoxW` FFI and `detect_reduce_motion`'s
`SystemParametersInfoW` FFI — avoids a direct `windows-sys` dep
that'd conflict with gpui_windows's transitive version on every
gpui bump. All ten out-args pass null because we don't want the
device, just the HRESULT.

On failure the process pops the same Windows error dialog flavour
as the existing fallback (caption + MessageBoxW) and exits with
code 0. The winget validator's 10-second launch test accepts
either a clean exit OR a still-running process — both outcomes
satisfy the validator, but the clean-exit path doesn't run any
gpui cleanup code so there's no RefCell to re-borrow and no
`STATUS_STACK_BUFFER_OVERRUN` to record.

Trade-offs:

  * Real-user UX on a genuinely broken GPU: same dialog, but the
    process now exits cleanly after dismissal rather than zombie-
    idling the empty event loop. Net better for users.
  * Probe overhead: one `D3D11CreateDevice` call per launch on
    Windows (~milliseconds on a healthy machine). Negligible.
  * MessageBoxW duplicates the FFI declaration from
    `show_window_open_error_dialog`. Two call sites is on the
    edge; if a third lands, refactor into a private
    `show_error_dialog` helper. Doc comment flags the threshold.
  * The existing `match open_app_window(...)` error path stays
    — the probe specifically catches the validator's
    no-adapter-at-all case, but non-DXGI window-open failures
    can still happen and need the safety net.

Followup once a real Windows-arm runner verifies the probe
works: restore arm64 to the winget manifest (TODO.md's "arm64
winget submission" item) and ship the next stable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds an on-demand trigger to release.yml so we can produce a
windows-arm64 build of a feature branch without tagging a
pre-release. Primary motivation: verify the DXGI probe (added in
the previous commit) on a real Windows-arm host before merging
the audit branch to main and tagging v0.12.5.

Surface:

  * `workflow_dispatch` with a single required `version` input
    (default `0.0.0-dev`). A hyphen in the value is treated as a
    pre-release marker the same way a tag would be, so MSI
    building is skipped — `ProductVersion` rejects alphanumeric
    segments and would fail the build. The bare .exe + NSIS
    installer + portable .zip still ship, which is what the probe
    test path actually needs.
  * Workflow-level `env.EFFECTIVE_VERSION` resolves the dispatch
    input or falls through to `github.ref_name`. All
    version-derivation sites (5 bash, 2 PowerShell, 3 pre-release
    `if:` gates, 1 GitHub-Release `prerelease:` flag) read this
    instead of `GITHUB_REF_NAME` so the dispatch path works
    without per-step plumbing.
  * The `release` job is gated to `github.event_name == 'push'`
    so workflow_dispatch runs DON'T create a GitHub Release.
    Artifacts land on the workflow-run page only (90-day
    retention, `gh run download <run-id>` for CLI access),
    keeping the Releases page uncluttered for ad-hoc testing.

GitHub only shows the "Run workflow" button if the trigger lives
on the default branch. This commit ships the trigger so the
audit branch can be tested via dispatch once it (or just this
commit, cherry-picked) lands on main.

The release notes step's `CURRENT_TAG="${GITHUB_REF_NAME}"` at
the release job stays unchanged — it lives in the job that's
gated to push events only, so `GITHUB_REF_NAME` is always a tag
there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same hygiene pass the root crate got in 7743a8e (Phase 1 of the
audit), now applied to the two helper crates under scripts/:

  * scripts/virtual-serial — the Rust virtual-serial test rig used
    by the manual smoke playbook in scripts/virtual-serial/TESTING.md.
  * scripts/transfer-tests — the automated wire-level XMODEM /
    YMODEM harness.

These aren't part of cargo's workspace (each has its own
Cargo.toml; the root crate doesn't `members =`), so the root
`cargo fmt` invocation skipped them, and the `cargo fmt --check`
CI step added in 96dfacf was checking only the root crate.

Two changes here:

  * Apply `cargo fmt` once to bring both scripts crates to the
    rustfmt baseline. ~240 lines reformatted across three files,
    pure whitespace + line-wrap normalisation; no behaviour or
    logic changes (these are dev-only tools that aren't built in
    the main binary, but `cargo build` per directory still
    succeeds — same code path the manual transfer-test runs
    exercise).

  * Extend the CI step (still on ubuntu-latest only) to loop over
    scripts/*/ and run `cargo fmt --check` in each. Same fast-fail
    placement before the platform deps install. New step name
    reflects the broader scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The branch CI's first dispatch run failed on the two Ubuntu
matrix entries with six dead-code errors in `serial::chipsets`:
ChipsetInfo, needs_driver, identify, is_suspect_product,
rebrand_for, chipset_from_manufacturer. macOS / Windows pass
because the consumers (`serial::detect`, `serial::usb_darwin`,
`serial::usb_windows`) ARE compiled on those platforms — but
all three of those modules are `#[cfg(any(target_os = "macos",
target_os = "windows"))]` per the `pub mod` declarations in
`serial/mod.rs`, so on Linux every chipsets item is unreachable.

I missed this in 247f7e4's narrowing pass — I only added an
item-level allow to `driver_url_for_vid` because the rest of the
file looked actively wired, not realising the wiring is
platform-conditional and Linux gets no callers.

Fix:

  * File-level `#![allow(dead_code)]` on chipsets.rs, with a
    doc-comment paragraph naming the platform-conditional callers
    so a future reader doesn't re-stumble into the same
    narrowing trap. Matches the pattern used by `usb_darwin`,
    `cp210x`, `direct`, `usbserial::mod` — the other modules in
    the same dead-on-Linux cluster.
  * Drop the now-redundant item-level `#[allow(dead_code)]` on
    `driver_url_for_vid`; the file-level one subsumes it.
  * `data/mod.rs` module-status comment: move `serial::chipsets`
    out of the "actively wired on all platforms" bucket into the
    "dead on Linux" bucket alongside the other libusb-direct
    siblings, with the same callsite explanation.

Verified locally on macOS (`cargo clippy --all-targets -- -D
warnings` + `cargo test` both clean) but the original failure
mode was Linux-only, so the actual confirmation comes from the
next dispatch run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surfaces a concrete user pain point flagged during the audit
branch's CI verification: the libusb-direct CP210x backend under
`src/data/usbserial/cp210x.rs` is fully implemented but not
wired into `serial_io::open`, so a Siemens RuggedCom RST2228
(CP210x rebrand at VID 0x0908 / PID 0x01FF, already in the
`REBRANDS` table) doesn't enumerate on macOS without SiLabs'
VCP kext installed — and the user can't connect.

The Tauri build had this fallback wired; the gpui rewrite went
`serialport`-only and never restored it. Code, tests, and
chipset table all carried forward intact; the missing piece is
the dispatch in `serial_io::open` ("OS port not found" branch
delegates to `usbserial::cp210x::open_port`) plus surfacing the
libusb-direct ports under the existing `usb:VID:PID:Serial`
name scheme that `data::serial::direct` defines.

Entry lands at the top of "Serial features (next tranche)"
without the **[on request]** marker — this isn't a hypothetical
feature ask, it's a real user with affected hardware.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both modules existed solely as consequences of Tauri's two-process
architecture (Rust backend ↔ JS frontend over IPC). gpui collapses
that into a single Rust process where UI + state share memory, so
both indirection layers became redundant on the rewrite:

  * `events.rs` — event-bus name constants (`"serial:data"`,
    `"settings:updated"`, etc.) + `TransferProgress` payload. The
    bus existed because the Rust serial read thread couldn't poke
    the xterm.js renderer directly. Replaced wholesale by direct
    `flume` channels into gpui entities + `SettingsBus`'s
    `cx.subscribe`/`cx.emit` pair.

  * `state.rs` — `AppState` singleton + `Mutex<HashMap<window_label,
    SessionHandle>>` + cross-window pending-payload HashMaps. The
    string-key indirection existed because Tauri commands address
    windows by label, and cross-window data handoff (terminal
    snapshots for session migration, initial profile ids for new
    windows) couldn't be passed by reference across the IPC
    boundary. Replaced by per-window state living on `AppView`
    directly + `AppShared` global for cross-window stores +
    `WindowInit::WithSession(SessionBundle)` for direct entity
    handoff at window-creation time.

247f7e4 flagged both as deletion candidates and gave them
file-level `#![allow(dead_code)]` to keep them compiling while
documented. Confirmed zero in-tree callers
(`grep -rn "data::events\|data::state\|TransferProgress\|AppState\|SessionHandle"`
returns nothing outside the deleted files), so the deletion is
mechanical — no follow-up wiring needed.

`data/mod.rs`'s status comment loses the "Tauri-era residue"
bullet and gains a closing note explaining what was removed +
why, so a future reader who finds an old git ref pointing at
the deleted files can still understand the architectural shift.

Verified: `cargo clippy --all-targets -- -D warnings` and
`cargo test` both pass (63 tests, unchanged).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Completes the scripts/* CI gate started in 4620d73 (which added
the fmt --check loop). That commit caught style drift but didn't
verify the scripts still compile — so a shared type change in
`src/data/transfer.rs` could break `scripts/transfer-tests`
silently, since the root `cargo clippy` / `cargo test` skip
the scripts/* crates entirely (they're not cargo workspace
members).

Runs as the last step on the existing ubuntu-latest gate
(co-located with fmt + deny). ubuntu-only because the scripts
target Unix and the apt-get step earlier in the matrix already
installs libudev for serialport. Cold compile is ~30 s per crate
(small dep trees — `serialport`, `ctrlc`, `serde`; no `gpui`);
incremental is a few seconds courtesy of Swatinem/rust-cache.

Doesn't ship the compiled binaries — pure compile verification.
The actual transfer-tests + virtual-serial workflows still live
under CONTRIBUTING.md's "Running tests" section as manual runs
from source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surfaces the v0.12.5 user-facing change so the next stable
release's auto-generated notes pick it up. Continues the v0.12.3
+ v0.12.4 boot-fix story: each prior fix uncovered the next
panic layer; the probe sidesteps the whole class by ensuring no
gpui state exists on the failure path.

Wording mirrors v0.12.3 / v0.12.4's entry shape (problem, what
v0.12.5 changes, what the user sees, validator-context note,
PR link). Pre-emptively cross-references microsoft/winget-pkgs
#377461 so a future reader following the story from CHANGELOG
can pull the validator's actual failure transcript.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The audit branch landed the DXGI probe (9fbfb9d) that fixes the
specific RefCell reentrancy the winget validator's headless arm64
sandbox tripped on v0.12.2 / v0.12.3 / v0.12.4. Captures the
state + ship sequence so future work doesn't re-derive what's
already fixed.

The entry is fresh on this branch — main + chore/audit don't
carry the equivalent "deferred arm64 winget submission" entry
that lives on docs/winget-install (commit 008c38c). Eventual
merge of docs/winget-install can drop its now-stale entry in
favour of this one, or reconcile in the merge.

Lives under ## Distribution next to the (completed) arm64 MSI
entry it logically follows — both are sequential steps in
getting arm64 winget users a native binary instead of the
current x64-via-emulation fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tips the call I left on the edge in 9fbfb9d. That commit's doc
flagged "two call sites is on the edge — if a third lands, the
FFI should move into a private helper." With both call sites
already in the tree (`show_window_open_error_dialog` from v0.12.3
+ `show_dxgi_unavailable_dialog` from this branch's probe), the
duplication is ~30 lines of identical wide-string + MessageBoxW
FFI per caller. Extracting now removes the duplication AND
removes the "on the edge" framing.

New shape:

  * `show_windows_error_dialog(caption: &str, body: &str)` — owns
    the OsStr-to-UTF-16 wide-string conversion, the MessageBoxW
    FFI declaration, and the `MB_OK | MB_ICONERROR` flags. Same
    doc block as the previous `show_window_open_error_dialog`
    explaining why inline FFI (no `windows-sys` dep), why the
    dialog doubles as a validator launch-test signal, etc.
  * `show_window_open_error_dialog<E: Debug>(err: &E)` — builds
    its body with the err interpolated, delegates. Loses its
    duplicate FFI block.
  * `show_dxgi_unavailable_dialog(hr: u32)` — builds its body
    with the HRESULT interpolated, delegates. Loses its
    duplicate FFI block.

Net: ~75 lines of duplicated FFI/wide-string boilerplate
collapses into a single ~40-line helper + two ~15-line
body-building callers. Same behaviour, easier to maintain
(future MessageBoxW flag tweaks, dialog title changes, or
wide-string handling fixes touch one place).

Updated `dxgi_probe`'s doc comment to reference
`show_windows_error_dialog` instead of the
now-thinner `show_window_open_error_dialog` for the inline-FFI
shape precedent.

Verified locally on macOS (`cargo clippy --all-targets -- -D
warnings` + `cargo test` both clean); Windows code is cfg-gated
so CI will verify the actual MessageBoxW compile on the next
dispatch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@packetThrower packetThrower merged commit c4a885c into main May 24, 2026
9 checks passed
packetThrower added a commit that referenced this pull request May 24, 2026
Moves the DXGI probe entry from [Unreleased] into a versioned
[0.13.0] section dated today (the day all four PRs landed on
main: #38 audit + probe, #39 macos-15-intel drop, #36 gpui bump
that subsumed #37 gpui_platform bump). Adds a [Changed] entry
for the gpui upstream-rev bump.

Per CONTRIBUTING.md, dev-tool / internal-refactor changes stay
out of CHANGELOG — the file splits, cargo-deny, workflow_dispatch,
fmt + scripts CI gates, Tauri-residue deletion all land in the
audit but don't surface to users beyond "things compile + run as
before." git log carries the per-commit detail for anyone
spelunking; the CHANGELOG entry is what shows up in the GitHub
Release body.

The release date is set to today (2026-05-24) since that's when
the v0.13.0 content was finalized on main. If the stable tag
lands days after the beta, the date can be bumped — but since
all content is already merged, today is the accurate "this is
what the release contains" anchor.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant