Scope: be/. This file is operational — what to do while developing or reviewing BE C++ code so the compile-time invariants hold. The gate mechanics and the *_fwd.h convention are documented in be/README.md (read it when a gate fires). Repository-wide rules (commit format, build/test commands, clang-format/clang-tidy) live in the root AGENTS.md; nothing here overrides them.
BE configure runs build-support/check-build-hygiene.sh (option ENABLE_BUILD_HYGIENE, default ON; scripts and self-tests live in build-support/ and build-support/tests/). It is pure text and takes about a second — run it directly after any change touching BE headers, includes, template instantiations, unity skip lists, or test files that include src sources; do not wait for configure or CI to tell you.
Every failure message carries the mechanism and the fix path. The legal way past a gate is never to bypass it, but one of:
.cpp, or route declarations through a *_fwd.h);ANGLE_BANS / FORWARD_CLOSURE_BUDGETS / REVERSE_REACH_BASELINES / PCH_QUOTED_WHITELIST / ALLOW) in the same commit and justify it in the commit message — the table diff is the review signal.#include to a widely-included (hub) header is a design decision, not a convenience. Everything a hub includes is reparsed by every TU behind it (~1000 TUs for exec_env.h, thread_context.h, runtime_state.h, function.h, dependency.h, column.h, ...). Prefer forward declarations; put the real include in the .cpp. If many files need the declarations, use a *_fwd.h (declarations and lightweight aliases only — never bodies or non-fwd project includes).pch/pch.h. Every header on the PCH rebuilds the whole backend (plus the PCH itself) when touched; it is the single most leveraged regression surface in the repo.extern template families paired. An explicit instantiation in a .cpp needs the matching extern template in the header, spelled with the same template arguments — a missing extern compiles and links fine and just silently re-instantiates in every TU. Instantiations expanded from macros (e.g. DECLARE_OPERATOR in operator.cpp) are invisible to the pairing gate on both sides: keep those in sync by hand.#includes a be/src .cpp needs that file opted out of unity batching via doris_skip_unity_inclusion in the owning be/src/.../CMakeLists.txt; otherwise the BE UT link fails with duplicate symbols an hour later. The gate error names the exact entry to add.fmt/boost/ concurrentqueue.h/<ranges>) to the headers listed in ANGLE_BANS: their bodies were deliberately moved out of line, and <ranges> in a src header additionally breaks the -fno-access-control UT build on libc++.*_fwd.h carry this instead? Does the PR pay a closure/reach budget bump — and if so, does the commit message justify it?RULES exceptions, budgets, whitelist, ALLOW) must be deliberate, minimal, and explained in the same commit; an unexplained table edit is a red flag, not a fix.pch/pch.h is near-always wrong; demand the reasoning.extern template blocks: both sides present, same spelling? New test #include of a src .cpp: skip entry present?git grep for a deleted/renamed header in skip lists and gate tables: stale entries fail configure loudly — fix them in the same PR.