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
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,22 @@ Current posture (as of Phase 9 entry, SHA `0433065c7`):

The `build.rs` / proc-macro / `macro_rules!` / codegen / env-var per-class contracts, the per-crate registry, the env-var registry, the workspace inventory script (`scripts/dev/build_codegen_audit.sh`), and the per-phase decisions log live in [`docs/architecture/code-quality/build_codegen_policy.md`](docs/architecture/code-quality/build_codegen_policy.md).

## Concurrency policy

UFFS enforces a strict task-ownership, lock-discipline, channel-backpressure, timeout-coverage, and blocking-IO posture in production async code. Three workspace Clippy lints at `deny` cover the std-side lock-across-await family (`await_holding_lock`, `await_holding_refcell_ref`, `await_holding_invalid_type`); the rest is enforced by `scripts/dev/concurrency_audit.sh` + a per-site annotation contract.

The one-line rule: **every `tokio::spawn` declares its owner / shutdown / errors / cancellation; every async lock guard is dropped before the next `.await`; every channel is bounded with documented capacity OR unbounded with a documented producer-rate ceiling; every cross-process / cross-thread / cross-network await has a timeout OR is justified as a cooperatively-cancelled forever-loop; every `std::fs::*` / `std::thread::sleep` inside an `async fn` is wrapped in `spawn_blocking` / `block_in_place` OR is a sync helper called only from sync contexts.**

Five dimensions, each with a taxonomy contributors quote inline:

- **Task ownership** (`T1` named-constructor / `T2` inline-spawn / `T3` fire-and-forget / `T4` test-only) — every prod spawn site documents the four facets above.
- **Lock discipline** (`L1`-`L5` patterns; `L6` lock-across-await is forbidden) — three Clippy `await_holding_*` lints at `deny`.
- **Channel discipline** (`C1` bounded / `C2` broadcast / `C3` oneshot / `C4` watch / `C5` unbounded-with-ceiling; `C6` undocumented unbounded is forbidden).
- **Timeout policy** (`W1` named const / `W2` env-overridable / `W3` cooperatively-cancelled forever-loop / `W4` inline literal; `W5` unbounded cross-process await is forbidden).
- **Blocking-IO rule** (`B1` `spawn_blocking` / `B2` `block_in_place` / `B3` sync helper / `B4` startup/Drop/CLI one-shot; `B5` unbounded sync I/O on runtime worker is forbidden).

Full taxonomy, per-site annotation templates, the workspace inventory script (`scripts/dev/concurrency_audit.sh`), per-crate posture matrix, and the per-phase audit trail live in [`docs/architecture/code-quality/concurrency_policy.md`](docs/architecture/code-quality/concurrency_policy.md).

## Docs map

- Root overview: `README.md`
Expand Down
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,18 @@ multiple_unsafe_ops_per_block = "deny" # Limit unsafe operations
unnecessary_safety_doc = "deny" # Accurate safety docs
unnecessary_safety_comment = "deny" # Accurate safety comments

# ───── Phase 10 concurrency discipline lints — see concurrency_policy.md §1 ─────
# The `await_holding_*` family lives in clippy's `suspicious` group, which
# defaults to `warn`. We pin all three at `deny` explicitly so the policy
# doc's enforcement claim is literally true (not "effectively at deny via
# `-D warnings` in CI") and survives any future tightening of the workspace
# `--deny warnings` shape. Triggering one is **never** acceptable in prod
# code — the canonical fix is the snapshot-then-await pattern documented in
# `concurrency_policy.md §2.2`.
await_holding_lock = "deny" # No std::sync::Mutex/RwLock guard across .await
await_holding_refcell_ref = "deny" # No RefCell::borrow{,_mut}() guard across .await
await_holding_invalid_type = "deny" # No Rc<T> / Cell<T> across .await (Send violation)

# ───── DENY level lints — safety, correctness, discipline ─────
# These MUST be clean in production code. clippy.toml relaxes test code
# automatically via allow-*-in-tests settings.
Expand Down
19 changes: 19 additions & 0 deletions crates/uffs-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@
//! All surfaces (CLI, TUI, GUI, MCP) use this crate to communicate with
//! the daemon. It handles auto-start, connection, keepalive, and reconnect.
//!
//! # Concurrency
//!
//! Hybrid runtime model:
//!
//! * [`connect::UffsClient`] (async; feature `async` default-on) — runs on the
//! caller's tokio runtime. Per-RPC `read_line` ceiling 300 s
//! (`Duration::from_mins(5)`; hard-coded). Notification channel is
//! `mpsc::unbounded_channel()` rate-bounded by the daemon's
//! `broadcast::Sender` capacity (Phase 10d C5 verdict).
//! * [`connect_sync::UffsClientSync`] (sync) — synchronous I/O on the caller
//! thread. Per-RPC deadline 60 s default, env-overridable via
//! `UFFS_CLIENT_TIMEOUT_SECS`; Windows path uses
//! `windows_deadline::WindowsDeadlineGuard` (a `CancelSynchronousIo`
//! watchdog, `#[cfg(windows)]`-only) to enforce the deadline on blocking pipe
//! I/O.
//!
//! See `docs/architecture/code-quality/concurrency_policy.md` for the
//! workspace contract.
//!
//! # Example
//!
//! ```rust,ignore
Expand Down
Loading
Loading