From d80664db5e667040ec12354047cf704aaf8919a2 Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 23 Jul 2026 18:26:24 +0800 Subject: [PATCH] =?UTF-8?q?docs(agents):=20=E6=96=B0=E5=A2=9E=E8=A7=84?= =?UTF-8?q?=E8=8C=83=20#16=E2=80=94=E2=80=94=E9=9D=9E=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=A6=81=E6=AD=A2=20unwrap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit panic="abort" 让进程级 panic 无法恢复,裸 unwrap 与之冲突。新增第 16 条 明确: - 默认走 ? / Result,经 AppError 或 Option 映射失败 - .expect("reason") 仅用于真正的不变量,消息必须解释为何不可能失败 - LazyLock 编译期常量、WASM 浏览器上下文、#[cfg(not(server))] stub、 bin 工具与 #[cfg(test)] 为豁免集 - 预留 clippy unwrap_used/expect_used lint 的 allow 范围 --- AGENTS.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 2b582aa..53058fa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -148,6 +148,14 @@ make docker-multiarch IMAGE=ghcr.io/owner/yggdrasil:latest # amd64+arm64, push 13. **WebP**: the `image` crate's `"webp"` feature is **intentionally excluded** — all WebP encode/decode goes through zenwebp (`src/webp.rs`). Do NOT add it. 14. **JS libs** (`libs/`): pnpm workspace, TypeScript strict (target ES2020, `verbatimModuleSyntax` ⟹ use `import type`), Biome formatter (2-space, single quotes, semicolons, `trailingCommas: all`, line width 100), Vite 8 IIFE bundles written into `../../public//`. `@yggdrasil/shared` is inlined into each IIFE — IIFEs cannot import each other at runtime. Use `make build-libs` or `make build-` (`pnpm --filter`). 15. **Heavy `//!` module docs explain WHY.** Read a module's top doc comment before editing it. User-facing strings are predominantly Chinese. +16. **No `unwrap()` in non-test code.** `panic = "abort"` (see Profile config) means any panic kills the whole process — there is no unwind, no recovery, just an immediate crash. This is incompatible with `unwrap()`'s "I'll deal with it later" semantics. Rules: + - **Default to `?` / `Result`** for fallible operations (DB, IO, parsing, header construction, regex compilation at call sites). Map failures through `AppError` (server) or return `Option` (WASM). + - **`.expect("reason")` is permitted only for true invariants** — cases where a `None`/`Err` would indicate a code bug, not a runtime condition. The message MUST explain *why* it cannot fail (e.g. `"val.max(1) 保证非零"`, `"etag 仅含 ASCII hex"`, `"静态 302 响应必然构造成功"`). A bare `.expect("TODO")` or `.expect("unreachable")` is equivalent to `unwrap` and is not acceptable. + - **`LazyLock` / `OnceLock` initialization of compile-time constants** (static `Regex`, `NonZeroU32::new(val.max(1))`, syntect's built-in `Plain Text` syntax) may use `.expect()` with an explanatory message — these run at most once and a failure means the source constant itself is wrong, which should surface immediately at startup, not silently degrade. + - **WASM browser-context calls** (`web_sys::window()`, `Reflect::get` on a known global) may use `.expect()` only inside `#[cfg(target_arch = "wasm32")]` / `#[component]` / `use_effect` scopes where a missing `window` proves the code is running outside a browser — a deployment bug, not a runtime input. + - **`unreachable!()` is permitted ONLY in `#[cfg(not(feature = "server"))]` stubs** of server functions — these branches are compiled out of the real server build and exist solely to satisfy the WASM target's type checker. + - **Build-tool binaries** (`src/bin/*`) and **`#[cfg(test)]` modules** are exempt — `unwrap`/`expect`/`panic` are idiomatic in tests and one-shot codegen tools. + - **If clippy's `unwrap_used` / `expect_used` lints are later wired in** (`[lints]` table in `Cargo.toml`), the exemptions above are the intended `allow` set; do not relax them further without a documented invariant. ## Workflow