diff --git a/AGENTS.md b/AGENTS.md index 9d18e662..ca6831b4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,6 +91,17 @@ If you find an asset that breaks these rules, stop and remove it from the reposi - **Track parity honestly.** Every user-facing feature has an entry in `parity/acrobat-features.toml`. Mark it `shipped` only when it works end to end and the entry cites a passing test (`evidence`); `cargo xtask parity` (part of `xtask ci`) rejects claims whose commands, tools or tests don't exist. - **Use it to test.** Agents should drive the engine through `printcraft-cli run --script` or the MCP tools, and look at `page_render` output, to check their own changes. For UI changes, launch the app with `--control` and use `printcraft-cli ui` (`inspect`, `click`, `screenshot`) to check the real interface. -## 4. Everything else +## 4. Never crash + +PrintCraft opens files from strangers. A malformed PDF, a bad tool argument or a corrupt settings file must produce an error the user (or agent) can act on, never a crash. + +- **Fail with `Result`.** Non-test code returns errors through the crate's error type and `?`. Where readers are lenient by design, fall back gracefully and record the repair (see Fidelity in `CLAUDE.md`). +- **No panicking shortcuts.** No `unwrap()`, `expect()`, `panic!`, `unreachable!`, `todo!` or `unimplemented!` outside tests, unless the call is provably infallible (e.g. writing to a `Vec`), with a comment saying why. `assert!` only for internal invariants that input cannot reach. +- **Treat every input-derived number as hostile.** Use `get()` instead of `[i]` or `[a..b]`. Slice strings only at char boundaries. Use checked/saturating arithmetic for lengths, offsets and counts. Guard against division by zero and NaN/inf casts, and never cast a negative value to `usize`. Cap allocations sized by the file. +- **Bound recursion.** Object graphs can be cyclic or deeply nested. Walk them with seen-sets or depth limits. +- **Don't cascade.** Handle lock poisoning, and keep a panic in a worker thread from taking the app down. Engine entry points that run untrusted-document code keep their last-resort `catch_unwind` guard. It is a safety net, not a substitute for the rules above. +- **Prove it.** Every crash fix comes with a small synthetic regression test that panicked before the fix. Turn fuzzer findings (`cargo xtask fuzz`) into such tests before fixing them. + +## 5. Everything else Follow `CLAUDE.md`. It covers quality gates, layering, commit rules and how to run and look at the app. diff --git a/CLAUDE.md b/CLAUDE.md index 2af43a8f..6e46da0d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,6 +19,13 @@ PrintCraft is a clean-room, open-source, Rust-native PDF application targeting A - **Privacy.** When observing Acrobat, use synthetic fixtures only. Never capture the Home view, recent files or account info. Capture by window id (`plan/acrobat/tools/`). Never commit Acrobat outputs, corpus files or personal data. - **Layering.** Nothing below L7 depends on egui/winit/eframe/rfd (`plan/architecture.md` §3). `cos`/`filters`/`crypt`/`arlington` stay standalone. - **Fidelity.** The PDF object graph is the model. Preserve unknown data. Saves are incremental unless a full rewrite is required. Never silently drop or repair data without recording it. +- **Never panic.** Every PDF, script, MCP call, settings file and keystroke is untrusted input, and none of it may crash the app. Return `Result` (the crate's error enum) and propagate with `?`, or fall back leniently and record it. In non-test code: + - No `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!` unless it is provably infallible, with a comment saying why. + - No indexing or slicing with input-derived positions (use `get`, and slice strings only at char boundaries). + - Use checked or saturating arithmetic on input-derived numbers, and guard against division by zero and NaN/inf casts. + - Cap allocations sized by input, and bound recursion with depth limits or seen-sets. + - Handle lock poisoning. + - Every crash fix gets a synthetic regression test. See `AGENTS.md` §4. - **Rust only** in the product and build (`xtask`). No handwritten JS/TS. - **Quality gates** before every commit: `cargo fmt --check`, `cargo clippy --workspace -- -D warnings`, `cargo test --workspace`, and the wasm check once `xtask ci` exists (M0). - **Commits:** one task id per commit (e.g. `M1.4: xref stream reader`). Commit only green states. End messages with the attribution line required by the environment.