Chat: Simplified Chinese. Code, commits, in-repo docs: English.
- Filenames:
snake_case.rsfor Rust source. kebab-case for configs, markdown, shell scripts. - Identifiers:
snake_casefor modules / functions / fields;PascalCasefor types / traits / enums;SCREAMING_SNAKE_CASEfor constants and statics; short lowercase for lifetimes ('a,'ctx). - Names describe what the thing does, not which vendor provides it.
handle_error, nothandle_sentry. Vendor names appear only in edge modules — the integration boundary where vane meets a dep. Internal logic stays brand-free.
rustfmt and clippy enforce most of this. Match their output.
- English, declarative, compact. State the non-obvious why — the constraint, the invariant, the workaround. Never the obvious what.
- One or two lines. A block over three lines usually means the function is under-named or over-scoped — fix the code.
- Public items get
///doc comments. Module-level overviews go in//!at the top of the file. - URLs in comments stay through any compression — they carry context the prose around them does not.
- No separator lines (
// ---,// ===,/* === */, ASCII art rules). If a section needs a heading, the function or module boundary already is the heading. - No commit/PR/issue references in source. Those live in git metadata.
cargo nextest run --workspace (or just test) is the canonical runner. cargo test --workspace (just test-cargo) is the bypass for doctests and runner-suspect debugging.
- Local dev target:
aarch64-apple-darwin. Cross-target coverage is CI's job. - Coverage floor: 95 % line coverage on tested modules. I/O error branches with no observable behavior may sit below — document the exemption in-module.
- What to cover: every public function gets a unit test covering the correct paths plus one representative error path. Exhaustive negative testing is not worth its maintenance cost.
- Redundancy rule: if
CorchestratesAandB, andA/Bhave their own tests,C's tests cover orchestration only. Don't re-verifyA's logic throughC. - Anti-over-testing: don't re-test
PredicateInst::testinside executor tests; don't re-test hyper's H1 encoding inside terminator tests; don't enumerate the 9-cell HTTP version matrix end-to-end (cover H1↔H1, H2↔H1, H1↔H2, trust hyper for the rest); don't assert hash-cons cache hits intest()calls.
tokio::time::sleep as a happens-before barrier is flake fuel. Gate on observable state.
- Push channel (broadcast, replay-less mpsc) — loop the trigger; each retry hits whatever subscriber state is current.
- Pull channel (mgmt verb, file probe) — loop the observation; the producer fires once.
- Negative-space assertion (system did not X within
N) — generous window, polled positive-invariant inside so a regression panics at first divergence.
Short sleeps inside a polling loop (50 ms cadence) are backoff, not barriers.
The agent that writes feature F does not write tests for F. Tests are written by a sub-agent with spec-only context. The asymmetry catches assumptions the implementation agent would otherwise ratify.
- Implementation agent commits feature on a branch.
- Sub-agent receives only the relevant spec sections, public type signatures, and
conventions.md. It writes failing tests, commits on a sub-branch, does not run them. - Implementation agent runs
cargo nextest run, classifies failures (test bug / impl bug / spec ambiguity), fixes accordingly. Spec-first when both diverge. - Merge commit records both authors via
Co-Authored-Bylines.
Pure-derive round-trip tests on #[derive(Serialize, Deserialize)] structs with no custom impls are exempt — there is no behavior beyond the derive.
vaned— full sub-agent automation. Daemon E2E tests spawnvaneddirectly viaassert_cmd/std::process::Command(the sharedvane-testutil::VanedFixturehelper is documentation-only today). Readiness: poll the listener port withTcpStream::connect_timeout; never parse stderr (tracing-subscriberfmtis block-buffered when stderr is not a TTY).vaneCLI — full automation.--jsonemits the verb'sresultverbatim; default pretty output auto-disables under!isatty(stdout). Test viaassert_cmd+predicates.vaneTUI — partial, when the views land. The currentvane tuiis a lifecycle scaffold only — seetui.mdand theTODO(tui-views)incrates/cli/src/tui.rs. Once the view set is implemented, automation covers the pure layer beneath the UI (data adapters, view state machine, input mapping); rendering and crossterm side-effects stay interactively verified.
Fixtures live in vane-testutil. Add helpers there, never in individual test files.