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
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
- Daemon, service, shortcut, path, and packaging changes often need updates across `src/daemon/`, `src/paths/`, `src/systemd_user_service.rs`, `src/shortcut_hint.rs`, `configurator/src/app/daemon_setup/`, and `packaging/`.

## Validation
- Full local CI is `./tools/lint-and-test.sh`.
- That script runs version/package checks, `cargo fmt --all -- --check`, clippy with all targets/features, all-feature tests, and no-default-feature tests.
- Full local CI is `./tools/lint-and-test.sh`. It needs the .NET SDK selected by `global.json`. Without it, `cargo test` still runs the Rust source guards in `tests/repository_guards` (process sites, config writers, shared dependencies, no Python), but not the C# checks, including the source-coverage check that finds `.rs` files Cargo never compiles.
- That script runs the C# repository checks (assets, version, nixpkgs recipe, source coverage, legacy tools), the C# tool tests (which also run the packaging shell contracts), `cargo fmt --all -- --check`, clippy with all targets/features, all-feature tests, and no-default-feature tests.
- Run `git diff --check` before handoff. When relevant files are untracked and the index must stay unchanged, check those files directly as well.
- For docs-only `AGENTS.md` edits, make new files visible to Git before whitespace checks, for example `rg --files --hidden -g AGENTS.md -0 | xargs -0 git add -N --` followed by `git diff --check`.
- On PowerShell, use `rg --files --hidden -g AGENTS.md | ForEach-Object { git add -N -- $_ }` followed by `git diff --check`.
Expand Down
56 changes: 31 additions & 25 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ Git hash, and tells Cargo which Git metadata should trigger a rebuild. Cargo fea

GitHub CI uses the C# file app. To run that route locally, build it once with
`dotnet build tools/wayscriber.cs`, then run commands with
`dotnet run tools/wayscriber.cs --no-build -- ...`. The standalone scripts remain
available for development and installation on machines without .NET. Nix does
`dotnet run tools/wayscriber.cs --no-build -- ...`. Repository, release, and
packaging checks exist only there, so the complete local gate needs .NET. Nix does
not provide .NET; `global.json` selects the required SDK when it is installed
separately.
separately. Without it, `cargo test` still runs the ownership guards in
`tests/repository_guards`, and the build, run, and install scripts stay usable;
the C# checks, including source coverage, need .NET.
The repository uses no Python.

Build both packages without launching a window:

Expand Down Expand Up @@ -128,12 +131,13 @@ Before submitting a broad or cross-package change, run the local CI entry point:
./tools/lint-and-test.sh
```

It checks release/package metadata, all three retained release contracts, package layout, Rust
source coverage, formatting, strict all-feature Clippy, all-feature tests, and no-default-feature
tests. When the pinned .NET SDK is installed, it also builds and runs the C# repository-tool tests;
otherwise it reports that optional local check as skipped. The source-coverage gate uses current
rustc dep-info and rejects tracked or unignored `.rs` files that are outside the supported Cargo
target/feature matrix.
It needs the pinned .NET SDK and stops without it. It checks release/package metadata, Rust
source coverage, and the shell-tool inventory; builds and runs the C# repository-tool tests,
which also run the package-layout and release-packaging shell contracts; then checks
formatting, strict all-feature Clippy, all-feature tests, and no-default-feature tests. The
Rust tests include the repository guards in `tests/repository_guards`. The source-coverage
gate uses current rustc dep-info and rejects tracked or unignored `.rs` files that are outside
the supported Cargo target/feature matrix.

The all-feature portal transport tests require `dbus-daemon`. Each fixture owns a private
session bus and connects through its explicit address, leaving the desktop session bus alone.
Expand Down Expand Up @@ -216,7 +220,8 @@ while preserving the original output identity and request. A second change durin
active-output switch is terminal. Board PDF desktop captures retain a full-desktop generation check,
including changes to other monitors even when the screenshot dimensions stay the same.

`./tools/code-health-report.sh` reports navigational maintainability metrics. Its CI artifact is
`dotnet run tools/wayscriber.cs --no-build -- report code-health` reports navigational
maintainability metrics. Its CI artifact is
observational, not a global file/function-size gate; use the report to find code worth understanding,
not as a reason for mechanical splitting.

Expand All @@ -226,32 +231,33 @@ not as a reason for mechanical splitting.
- Installation, service, and shortcut behavior belongs in `docs/SETUP.md` and packaging docs.
- Main-crate architecture belongs in `docs/codebase-overview.md`.
- Drafts under `docs/temp/` are planning material unless explicitly promoted.
- Version changes must go through `tools/bump-version.sh`; keep both package manifests, root
`Cargo.lock`, packaging metadata, and tag/release policy aligned.
- Version changes must go through the C# `version bump` command; keep both package manifests,
root `Cargo.lock`, packaging metadata, and tag/release policy aligned.
- Close a user-visible "I don't have that setting / this build" report only after the change is in
a tagged GitHub release. `main` is not what `arch-install.sh`, AUR `wayscriber-bin`, or other
packaged installs ship. `--version` reports the crate version, not the git hash, so bump with
`tools/bump-version.sh` in the same change as a user-visible overlay, settings, or config toggle
`version bump` in the same change as a user-visible overlay, settings, or config toggle
(or immediately before tagging that release). Otherwise two binaries can print the same
`wayscriber 0.9.x` and look identical.

See [tools/README.md](tools/README.md) for build, install, packaging, version, and release helpers.

Run `./tools/lint-and-test.sh` for the standalone local gate. It lints, builds
binaries, and tests the whole workspace with all features and with no default
features, alongside source, packaging, retained release-contract, and C# tool
checks when .NET is installed. CI runs the equivalent C# command and additionally checks dynamic
Run `./tools/lint-and-test.sh` for the complete local gate; it needs the .NET SDK
selected by `global.json`. It builds the C# tools, then runs the same steps as CI's
`ci lint-and-test`: the C# repository checks, C# formatting, and the C# tests
(which run the retained packaging shell contracts), then lints, builds binaries,
and tests the whole workspace with all features and with no default features. CI runs the equivalent C# command and additionally checks dynamic
and static gtk4-layer-shell linkage and uploads its code-health report.

GTK widget coverage runs separately with `./tools/test-gtk-widgets.sh` (Weston,
`dbus-run-session`, Python 3, `pkg-config`, Mesa software OpenGL, and Wayland
protocol XML required). It creates a private headless display and requires GTK
initialization; an unavailable display fails this check. The native popup tests
use another private Weston with software OpenGL and a protocol proxy to hold one
popup frame callback while its shared clock paints, then require capture to finish
after the popup's fresh render is acknowledged. They cover a plain `GtkPopover`
and `GtkPopoverMenu`'s empty proof overlay and menu restoration. Successful bodies
print `EXECUTED` markers. Ordinary widget tests without a display report an
`dbus-run-session`, and Mesa software OpenGL required). It creates a private
headless display and requires GTK initialization; an unavailable display fails
this check. The native popup tests use another private Weston with software
OpenGL and a Rust protocol proxy to hold one popup frame callback while its
shared clock paints, then require capture to finish after the popup's fresh
render is acknowledged. They cover a plain `GtkPopover` and `GtkPopoverMenu`'s
empty proof overlay and menu restoration. Successful bodies print `EXECUTED`
markers. Ordinary widget tests without a display report an
optional skip; when a display is available, their GTK assertions run. The native
popup tests require the dedicated GTK gate. Neither route proves layer-shell
focus or screen capture behavior on a user's compositor.
18 changes: 13 additions & 5 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ Land tooling fixes, test routing, and release documentation as focused commits,
then commit the version bump separately immediately before tagging. An uncommitted
release preparation may contain these groups together; stage them separately at handoff.

1. Run `./tools/bump-version.sh X.Y.Z`. It updates both workspace versions and
package metadata without refreshing locked dependencies. Review `Cargo.lock`:
The version and tag steps use the C# repository tool. Build it once with
`dotnet build tools/wayscriber.cs`; the commands below then run it with `--no-build`.

1. Run `dotnet run tools/wayscriber.cs --no-build -- version bump X.Y.Z`. It updates
both workspace versions and package metadata without refreshing locked dependencies,
then runs `version check --release-version X.Y.Z`. Review `Cargo.lock`:
a version-only release should change only the two workspace package versions.
Prefetch dependencies first if the local Cargo cache is empty.
If the local Cargo cache is empty, the bump stops before it changes a file; prefetch
dependencies with `dotnet run tools/wayscriber.cs --no-build -- dev fetch` first.
2. Run `./tools/lint-and-test.sh` and `./tools/test-gtk-widgets.sh`. The canonical
gate serializes the Rust test harness to avoid the observed parallel native-font
crashes. It also runs each context-menu and board-picker retained-text rendering regression
Expand All @@ -27,8 +32,11 @@ release preparation may contain these groups together; stage them separately at
## Publish and verify

After reviewing and committing the release changes, push the branch and wait for
its GitHub checks. Use `./tools/publish-release-tag.sh --version X.Y.Z` only when
ready to publish. It creates and pushes the tag; the tag starts the Release workflow.
its GitHub checks. Use
`dotnet run tools/wayscriber.cs --no-build -- release publish-tag --version X.Y.Z`
only when ready to publish. It repeats the version check for that release version,
requires a clean working tree and an unused tag, and then creates and pushes the tag;
the tag starts the Release workflow. Add `--dry-run` to run the checks without tagging.

Verify the whole Release workflow, including the GitHub assets, AUR recipes, and
apt/rpm repository deployment. AUR waits for successful GitHub asset publication.
Expand Down
6 changes: 3 additions & 3 deletions docs/codebase-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ capture suppression operates on the paired resources without runtime pairing che
slot, quick color), which each rewrite one key. Everything else — the overlay's other controls,
the daemon, the tray, startup, validation, migration preview, and shutdown — reads the file and
leaves its bytes, mode, and mtime alone, including for a missing, read-only, or old-revision
file. `tools/check-config-writers.py` pins that set by name.
file. `tests/repository_guards/config_writers.rs` pins that set by name.
- Every one of those writes goes through `ConfigDocument::save_with_backup`, which holds an
advisory lock on a sibling `config.toml.lock` across the whole check-copy-rename window
(`src/config/document/lock.rs`). The revision check and the atomic rename are separate syscalls
Expand Down Expand Up @@ -423,7 +423,7 @@ capture suppression operates on the paired resources without runtime pairing che
submission joins a staging queue in front of the channel and is pumped in as the worker makes
room, so a burst that fills the channel cannot answer the newest gesture ahead of the older ones
it was made after (which would leave their completions applying on top of it). That module is the
only production caller of the three editors, and is what `tools/check-config-writers.py` pins.
only production caller of the three editors, and is what `tests/repository_guards/config_writers.rs` pins.
- Teardown is `finish_config_edits` (called by `shutdown_config_edits`, beside
`shutdown_runtime_ui`). It drains `InputEffectDrain::DurableConfig` — the outbox-owned inventory
of preset, quick-color, and recorded shortcut edits — one last time before stopping the worker,
Expand Down Expand Up @@ -486,7 +486,7 @@ capture suppression operates on the paired resources without runtime pairing che
then arbitrated by traversal order instead of being filtered away as an unauthored default, and
the configurator's save status names which action kept the key: the resolution reaches
`config.toml`, so the reloaded document has nothing left to report.
- Two guards keep it that way: `tools/check-config-writers.py` (in `tools/lint-and-test.sh`) fails
- Two guards keep it that way: `tests/repository_guards/config_writers.rs` (in every `cargo test`) fails
when any source outside `src/config/document.rs`, `src/config/io.rs`, and
`configurator/src/app/io.rs` names a config write primitive, when an unpinned file calls one of
the narrow editors, or when the editors' path-taking `_at` twins stop being `#[cfg(test)]`-gated
Expand Down
2 changes: 1 addition & 1 deletion docs/daemon-protocol-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ process-start identity. The daemon does not mark that child ready until all thre
exit is watched through the pidfd, while signals, tray intents, shortcut intents, and typed queue
renames have owned wake descriptors; the daemon lifecycle has no periodic discovery tick.

The enforced process-site inventory is `tools/check-process-sites.py`. Direct process creation is
The enforced process-site inventory is `tests/repository_guards/process_sites.rs`. Direct process creation is
limited to the broker, pre-runtime systemd setup, the separate configurator process, standalone
About clipboard integration, and named test fixtures. The same check audits the raw-clone child
stub: before `execve` it may reach only the fixed `fcntl`, `dup3`, `setpgid`, `close_range`,
Expand Down
4 changes: 2 additions & 2 deletions packaging/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
- Packaging changes may require `tools/`, `.github/`, setup docs, `src/systemd_user_service.rs`, `src/shortcut_hint.rs`, and configurator daemon setup updates.

## Validation
- Run `tools/check-version-consistency.sh` and `tools/test-package-repo-layout.sh` for package/version changes.
- Run `tools/check-nixpkgs-recipe.py` when dependencies, default features, or Nix build inputs change.
- Run `dotnet run tools/wayscriber.cs --no-build -- version check` and `tools/test-package-repo-layout.sh` for package/version changes.
- Run `dotnet run tools/wayscriber.cs --no-build -- check nixpkgs-recipe` when dependencies, default features, or Nix build inputs change.
- Run `git diff --check` for metadata-only edits.
2 changes: 1 addition & 1 deletion packaging/nixpkgs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ We do not own that file — `nixpkgs` does. This copy exists so that:

- packaging changes here (new system libraries, new installed files) are visible
in the same commit as the change that requires them, and
- `tools/check-nixpkgs-recipe.py` can fail CI when a default Cargo feature needs
- `dotnet run tools/wayscriber.cs --no-build -- check nixpkgs-recipe` can fail CI when a default Cargo feature needs
a system library the `nixpkgs` build does not declare.

## How versions reach nixpkgs
Expand Down
2 changes: 1 addition & 1 deletion packaging/nixpkgs/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ rustPlatform.buildRustPackage (finalAttrs: {

# Keep in sync with the default feature set in Cargo.toml; the GTK inputs are
# required by the `toolbar-gtk` default feature.
# Checked by tools/check-nixpkgs-recipe.py.
# Checked by `dotnet run tools/wayscriber.cs --no-build -- check nixpkgs-recipe`.
buildInputs = [
cairo
gtk4
Expand Down
4 changes: 2 additions & 2 deletions src/config/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ pub(crate) fn is_stale_source_error(error: &anyhow::Error) -> bool {
/// non-idempotent validation step appears. Two things defend it in place of a
/// behavioural test: `document_config_is_a_fixed_point_of_validation` below,
/// which fails the moment validation stops being idempotent, and the
/// `authored_config()` check in `tools/check-config-writers.py`.
/// `authored_config()` check in `tests/repository_guards/config_writers.rs`.
///
/// `verify` runs afterwards against the document the save parsed from the bytes
/// it wrote — the merge output, not a re-read of the file — so a value that
Expand Down Expand Up @@ -465,7 +465,7 @@ pub fn persist_keybinding_edit(action: Action, bindings: &[String]) -> Result<Co
/// Test-only, and gated rather than merely `pub(crate)`: production has no use
/// for a config path that did not come from the environment, and a build that
/// cannot name this cannot acquire one by accident. The name is still pinned in
/// `tools/check-config-writers.py`, which fails a production caller with a
/// `tests/repository_guards/config_writers.rs`, which fails a production caller with a
/// message about the gesture rather than a resolution error.
#[cfg(test)]
pub(crate) fn persist_keybinding_edit_at(
Expand Down
5 changes: 3 additions & 2 deletions src/daemon/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
- Applies to daemon lifecycle, toggle protocol, runtime files, tray integration, setup helpers, global shortcuts, overlay process control, and daemon tests.

## Architecture
- `core.rs`, `control.rs`, and `types.rs` own daemon state and toggle/control behavior.
- `core.rs` coordinates daemon control, command authorization and runtime events; `control.rs` and `types.rs` define toggle/control requests and shared types.
- `binary_conflict.rs` warns when another Wayscriber binary exists besides the running daemon.
- `overlay/` owns overlay process spawn/control.
- `overlay/launch.rs` owns resolved launch options and activation tokens; `overlay/mod.rs` queues and consumes them, preserving token-only retention on existing early-error paths.
- `overlay/lifecycle.rs` owns overlay visibility, active target/flag, backoff, start and retirement; `overlay/lifecycle/stop.rs` owns graceful/forced shutdown. `protocol_v2::OverlayChildOwner` retains child identity, proof records and reaping.
- `tray/` owns tray integration and shortcut hint I/O.
- `setup.rs` and `global_shortcuts.rs` support daemon setup workflows.
- `update_watch.rs` owns the background update notice: it publishes to `TrayStatusShared`
Expand Down
Loading
Loading