C++ Review
Review C++ changes and report issues by severity. Project rules below take
precedence over the general guidelines when the two conflict.
This skill covers two repositories that are one product:
| Repo |
Role |
Remote |
Integration branch |
depthai-core |
Host SDK. Public C++/Python API. |
github.com/luxonis/depthai-core |
develop |
depthai-device-kb |
Device firmware for RVC4. |
|
develop |
depthai-device-kb holds depthai-core as a submodule at
external/depthai-core. Both repos compile the same public headers. Find
out which repo you are in before you apply a rule as some rules apply to one
repo only.
The SDK is the primary way to use Luxonis RVC2 (OAK 1 and OAK 2) and RVC4
(OAK 4) hardware. Tests must use real hardware when the feature needs it.
Scope
If $ARGUMENTS names a path, commit range, or PR, review that. Otherwise:
git diff --stat -- '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.h'
git diff -- '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.h'
Review only modified files and their immediate call sites. Do not audit the
whole repo. Never review vendored or submodule trees:
3rdparty/, shared/, include/3rdparty/, bindings/python/external/,
external/ (device-kb), vcpkg/, and any build*/ directory.
Run static analysis first
Run whichever are available; skip silently if not installed. Both repos share
an identical .clang-format. Use clang-format-18 and clang-tidy-18
only as CI pins those versions.
cmake -S . -B build -DDEPTHAI_CLANG_FORMAT=ON
cmake --build build --target clangformat
git --no-pager diff # any diff here is a CI failure
# tidy (depthai-core)
cmake -S . -B build -DDEPTHAI_CLANG_TIDY=ON -DCLANG_TIDY_BIN=/usr/bin/clang-tidy-18
# consistency gates (depthai-core only - these are hard CI gates)
bash ci/check_datatype_enum_consistency.sh
bash ci/check_protobuf_consistency.sh
Report analyser findings alongside your own. Do not simply relay the tool
output and flag which findings are real and which are noise in this
codebase. The "Known exceptions" list at the end of Part 1 tells you what is
noise here.
PART 1 — PROJECT RULES (highest priority)
A. Cross-repo contract
Wire-format and ABI compatibility across host and device.
DEPTHAI_SERIALIZE / DEPTHAI_SERIALIZE_EXT field lists the
DatatypeEnum order, and every Properties struct are the serialised
contract between the host SDK and device firmware. Both sides compile the
same header, but a host and a device of different versions talk to each
other in the field.
Flag any of these in a shared type
(include/depthai/pipeline/datatype/, include/depthai/properties/,
include/depthai/common/):
- a field reordered, renamed, retyped, or removed from a
DEPTHAI_SERIALIZE* list;
- a
DatatypeEnum enumerator inserted in the middle, reordered, or
removed. New values append at the end, before COUNT;
- a new field with no default value.
Correct pattern: append the field at the end of the struct and at the
end of the DEPTHAI_SERIALIZE* list, with a default initialiser.
Severity: CRITICAL
B. Backward compatibility
Every change must be backward compatible.
A new parameter needs a new overload, an optional, or a default value.
Severity: CRITICAL
Removal and renaming go through deprecation.
Keep the old symbol and mark it
[[deprecated("Use <replacement> instead")]]. The message must name the
replacement — that is the house pattern
(XLinkConnection::getMxId, ColorCamera::setCamId, PointCloudData::isSparse).
Deleting a public symbol outright is a break.
Severity: CRITICAL
C. Build system
C++17 is the hard target.
Flag all features that use C++20 or later.
Severity: HIGH
Formatting is enforced by CI, not by opinion.
ci/check_format.sh <builddir> fails on any diff after
--target clangformat. Do not hand-format; do not fight the tool.
Severity: MEDIUM
D. Adding a datatype (depthai-core)
Two CI scripts encode this as a hard gate. A new or changed message must
satisfy all of it. Use the scripts as the checklist:
ci/check_datatype_enum_consistency.sh requires:
- The class lives in
include/depthai/pipeline/datatype/<Name>.hpp and
inherits Buffer.
getDatatype() returns DatatypeEnum::<Name>, and <Name> exists in
include/depthai/pipeline/datatype/DatatypeEnum.hpp - appended, never
inserted.
<Name> appears as a key and as a child entry in the hierarchy map in
src/pipeline/datatype/DatatypeEnum.cpp.
src/pipeline/datatype/StreamMessageParser.cpp has a
case DatatypeEnum::<Name>: return parseDatatype<Name>(...).
serialize(std::vector<std::uint8_t>&, DatatypeEnum&) const override is
implemented, and the class ends with
DEPTHAI_SERIALIZE(<Name>, Buffer::sequenceNum, Buffer::ts, Buffer::tsDevice, Buffer::tsSystem, <fields...>);
ci/check_protobuf_consistency.sh requires, if the message is protobuf
serialisable:
- A
.proto in protos/, registered in protos/CMakeLists.txt.
serializeProto / deserializeProto / serializeSchema overrides inside
#ifdef DEPTHAI_ENABLE_PROTOBUF, and the class also inherits
ProtoSerializable.
getProtoMessage(const <Name>*) declared in src/utility/ProtoSerialize.hpp
and defined in src/utility/ProtoSerialize.cpp — the two sets must
match exactly.
- If deserialisation is supported:
setProtoMessage(<Name>&) in both files,
a schemaNameToDatatype mapping, and the enum listed in
deserializationSupported.
Severity: HIGH
E. Tests
Every new node, message, feature, and bugfix needs a test.
The test must exercise the real behaviour, not just construct the object.
Severity: HIGH
Serialization roundtrip
Any change to a type deriving from include/depthai/pipeline/datatype/Buffer.hpp
needs a serialization roundtrip test that runs on both RVC2 and RVC4.**
Severity: HIGH
F. Python bindings (depthai-core only)
All public C++ API must be exposed to Python. depthai-device-kb has
no bindings, so this rule does not apply there.
A new public class needs
bindings/python/src/<mirrored path>/<Name>Bindings.cpp with:
void bind_<name>(pybind11::module& m, void* pCallstack),
- all
py::class_ / py::enum_ declarations first, then the
callstack push/pop block, then the actual .def(...) bindings — this
two-phase order is what makes forward references work;
DOC(dai, <Name>) on every class and method;
PYBIND11_MAKE_OPAQUE(std::vector<dai::T>) plus
py::bind_vector and py::implicitly_convertible<py::list, std::vector<T>>()
for any new vector type crossing the boundary.
Register the file in bindings/python/CMakeLists.txt and push its bind
into the callstack.
Severity: HIGH
Doxygen comments are the Python docstrings.
DOC(dai, X) is generated from the header comment by pybind11_mkdoc. A
missing or stale Doxygen comment silently ships an empty or wrong Python
docstring. Every public function needs one:
/**
* Set edges connections between keypoints.
* @param edges Vector edges connections represented as pairs of keypoint indices.
* @note This is only applicable if keypoints decoding is enabled.
*/
void setKeypointEdges(const std::vector<dai::Edge>& edges);
Severity: MEDIUM - raise to HIGH when the symbol is bound to Python.
G. Examples (depthai-core only)
- C++ and Python examples are mirrored.
examples/cpp/<Category>/<snake_case>.cpp must have a matching
examples/python/<Category>/<snake_case>.py. A new C++ example without its
Python twin is a finding, and the same the other way round. Register the
C++ one with dai_add_example.
Severity: MEDIUM
H. Node structure
Host-side node (depthai-core).
class ImageAlign : public DeviceNodeCRTP<DeviceNode, ImageAlign, ImageAlignProperties>
public:
constexpr static const char* NAME = "ImageAlign";
using DeviceNodeCRTP::DeviceNodeCRTP;
protected:
Properties& getProperties() override;
Input and Output members are declared inline with their queue config
and accepted datatypes:
Input input{*this, {"input", DEFAULT_GROUP, false, 4, {{DatatypeEnum::ImgFrame, false}}}};
A pure host node derives from CustomThreadedNode<T> / ThreadedHostNode.
Device-side node (depthai-device-kb).
Lives in namespace dai { namespace gate {, derives the core
dai::node::<X>, and overrides run(), buildStage1(), and
runOnHost(). Its NAME aliases the core node's NAME. A device node
must also appear in src/pipeline/PipelineBuilder.cpp, otherwise the
pipeline cannot instantiate it.
Run loops use while(mainLoop()), not while(isRunning()).
mainLoop() also drives pipeline debugging and state reporting.
Wrap a blocking input read in auto blockEvent = this->inputBlockEvent();
and a blocking send in outputBlockEvent(), so the queue-blocking stats in
PipelineDebugging.md stay correct.
Severity: MEDIUM
Setters return the node by reference for chaining
(ImageAlign& setNumShaves(int numShaves);) and write into properties.
Severity: LOW
I. Reuse existing code
New features and nodes must reuse what exists. Search before you add a
helper — include/depthai/utility/ already holds matrixOps.hpp,
span.hpp, Serialization.hpp, ImageManipImpl.hpp, LockingQueue.hpp,
CircularBuffer.hpp, Pimpl.hpp, RecordReplay.hpp, Clock.hpp,
Memory.hpp, and more; include/depthai/common/ holds the shared value
types. Cite the existing equivalent if one exists.
For a genuinely new helper, judge where it belongs: node-agnostic logic, or
logic with a second caller in sight, belongs in utility/ or common/;
anything tied to a node's internals stays local to that node. Do not promote
speculatively. Near-duplicate blocks across nodes are candidates for a common
version.
Severity: MEDIUM
J. Naming and style
House style, confirmed across both repos. This overrides the general
guidelines in Part 2 where the two disagree.
| Kind |
Convention |
Example |
| Class, struct, enum, and its file name |
PascalCase |
ImgFrame, ImageAlignProperties.hpp |
| Function, method, variable, member |
camelCase |
setNumShaves, alignWidth |
| Enumerator |
ALL_CAPS |
CameraBoardSocket::CAM_A |
| Compile-time constant |
ALL_CAPS |
DEFAULT_QUEUE_SIZE |
| Namespace |
lowercase |
dai, dai::node, dai::gate |
| Check every modified file, examples included. |
|
|
| Severity: MEDIUM |
|
|
PART 2 — GENERAL C++ STANDARDS
Derived from the C++ Core Guidelines. Rule IDs (R.11, ES.20, …) refer to
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines — cite them in
findings so the author can look up the rationale.
CRITICAL — Memory safety
- Raw
new/delete instead of unique_ptr/shared_ptr or RAII (R.11, R.20)
malloc/free in C++ code (R.10)
- Buffer overflows: C arrays,
strcpy, sprintf without bounds (SL.con.1)
- Use-after-free: dangling pointers, invalidated iterators
- Uninitialized variables read before assignment (ES.20)
- Missing null check before pointer dereference
- Returning a pointer or reference to a local (F.43)
- Resources not tied to object lifetime (P.8, E.6)
CRITICAL — Security
- Command injection via unvalidated input to
system() / popen()
- Format string attacks: user input as a
printf or fmt format
- Unchecked integer arithmetic on untrusted input (ES.46, ES.100)
- Hardcoded secrets, API keys, passwords in source
reinterpret_cast without documented justification (ES.48)
- Casting away
const (ES.50)
HIGH — Concurrency
- Data races: shared mutable state without synchronisation (CP.2, CP.3)
- Deadlocks: multiple mutexes taken in inconsistent order — use
std::scoped_lock (CP.21)
- Manual
lock()/unlock() instead of RAII guards (CP.20)
- Unnamed lock guards —
std::lock_guard<std::mutex>(m); destroys immediately
(CP.44)
- Detached threads without lifetime management (CP.26)
- Waiting on a condition variable without a predicate (CP.42)
- Calling unknown code (callbacks) while holding a lock (CP.22)
volatile used for synchronisation (CP.8)
- Node-specific: blocking on an input queue outside a
mainLoop() iteration,
or holding a lock across a queue get() — the node cannot then be stopped.
HIGH — Class design and code quality
- Rule of Five violated: some special members defined, others missing (C.21)
- Special members defined where Rule of Zero would do (C.20)
- Base class destructor neither public-virtual nor protected-non-virtual (C.35)
- Single-argument constructor not
explicit (C.46)
- Virtual functions without exactly one of
virtual/override/final (C.128)
- Virtual calls in constructors or destructors (C.82)
memset/memcpy on non-trivial types (C.90)
- Missing
const correctness on methods, parameters, references (Con.2, Con.3)
- Functions over ~50 lines or doing more than one thing (F.2, F.3)
- Nesting deeper than 4 levels
- C-style code:
typedef over using (T.43), C arrays, C-style casts (ES.48)
- Non-const globals (I.2)
- Ownership transferred by raw pointer or reference (I.11, R.3)
MEDIUM — Performance
- Large objects passed by value where
const& is right (F.16)
- Missing
std::move on sink parameters
- Missing
reserve() on known-size containers
- String concatenation in loops
- Compile-time-computable work left at runtime (Per.11)
- Pointer-chasing layouts where contiguous storage would do (Per.19)
- Optimisation claims without measurement (Per.6) — flag both unmeasured
optimisation and premature complexity
- Copying an
ImgFrame payload where a span or shared Memory would do
MEDIUM — Idiom and hygiene
- Not
const/constexpr by default (Con.1, ES.25)
0/NULL instead of nullptr (ES.47)
- Narrowing or signed/unsigned mixed arithmetic (ES.46, ES.100)
using namespace at global scope in a header (SF.7)
- Headers not self-contained (SF.8)
std::endl instead of '\n' (SL.io.50)
- Output parameters where a returned struct is clearer (F.20, F.21)
- Exceptions: built-in types thrown, caught by value, empty catch blocks,
exceptions used for flow control (E.14, E.15, E.3)
Output format
# C++ Review
## Scope
<repo, files reviewed, commit range or PR>
## Static analysis
clang-format-18: <clean | n files would change>
clang-tidy-18: <n> findings (<n> actionable)
datatype consistency: <PASS | FAIL | n/a>
protobuf consistency: <PASS | FAIL | n/a>
build: <clean | n warnings>
## Findings
### [CRITICAL] <one-line title> (PROJECT: <rule name> | <Core Guideline ID>)
`path/to/file.cpp:45`
<one or two sentences: what's wrong and what goes wrong because of it>
Current:
```cpp
<minimal excerpt>
```
Suggested:
```cpp
<the fix>
```
### [HIGH] ...
### [MEDIUM] ...
### [INFO] ...
## Checked and clean
<one line each: what you verified and found correct>
## Summary
CRITICAL: n HIGH: n MEDIUM: n INFO: n
Verdict: APPROVE | WARN | BLOCK
Verdict rules
| Verdict |
Condition |
| APPROVE |
No CRITICAL or HIGH findings |
| WARN |
MEDIUM findings only — merge with judgement |
| BLOCK |
Any CRITICAL or HIGH finding |
Any violation of a Part 1 project rule marked CRITICAL blocks on its own,
regardless of what Part 2 turns up.
Reviewing discipline
- Every finding needs a file and line. No findings without a location.
- One finding per problem. Don't restate the same issue per call site — cite
the first and note the count.
- Suggest a fix, don't just name the rule.
- Say what you checked and found clean, briefly. A review that only lists
problems hides its own coverage gaps.
- If a change is correct but the surrounding design makes it fragile, say so
under INFO rather than inflating the severity.
- Don't flag anything listed under "Known exceptions".
- State which repo you reviewed. A rule from the wrong repo is a false
positive.
1---2name: depthai-cpp-review3description: Reviews C++ changes against this project's rules plus modern C++ Core Guidelines — memory safety, concurrency, security, performance, and idiom. Use for any C++ code review, before committing or merging C++ changes, and whenever the user asks to check, review, or audit .cpp/.hpp/.cc/.h files. Also use proactively after writing or refactoring C++ in this repo.4---56# C++ Review78Review C++ changes and report issues by severity. Project rules below take9precedence over the general guidelines when the two conflict.1011This skill covers two repositories that are one product:1213| Repo | Role | Remote | Integration branch |14| -------------------- | ------------------------------------------ | ------------------------------------------------------ | ------------------ |15| `depthai-core` | Host SDK. Public C++/Python API. | `github.com/luxonis/depthai-core` | `develop` |16| `depthai-device-kb` | Device firmware for RVC4. | | `develop` |1718`depthai-device-kb` holds `depthai-core` as a submodule at19`external/depthai-core`. Both repos compile the same public headers. Find20out which repo you are in before you apply a rule as some rules apply to one21repo only.2223The SDK is the primary way to use Luxonis RVC2 (OAK 1 and OAK 2) and RVC424(OAK 4) hardware. Tests must use real hardware when the feature needs it.2526## Scope2728If `$ARGUMENTS` names a path, commit range, or PR, review that. Otherwise:2930```bash31git diff --stat -- '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.h'32git diff -- '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.h'33```3435Review only modified files and their immediate call sites. Do not audit the36whole repo. Never review vendored or submodule trees:37`3rdparty/`, `shared/`, `include/3rdparty/`, `bindings/python/external/`,38`external/` (device-kb), `vcpkg/`, and any `build*/` directory.3940## Run static analysis first4142Run whichever are available; skip silently if not installed. Both repos share43an identical `.clang-format`. **Use clang-format-18 and clang-tidy-1844only** as CI pins those versions.4546```bash47cmake -S . -B build -DDEPTHAI_CLANG_FORMAT=ON48cmake --build build --target clangformat49git --no-pager diff # any diff here is a CI failure5051# tidy (depthai-core)52cmake -S . -B build -DDEPTHAI_CLANG_TIDY=ON -DCLANG_TIDY_BIN=/usr/bin/clang-tidy-185354# consistency gates (depthai-core only - these are hard CI gates)55bash ci/check_datatype_enum_consistency.sh56bash ci/check_protobuf_consistency.sh57```5859Report analyser findings alongside your own. Do not simply relay the tool60output and flag which findings are real and which are noise in this61codebase. The "Known exceptions" list at the end of Part 1 tells you what is62noise here.6364---6566# PART 1 — PROJECT RULES (highest priority)6768## A. Cross-repo contract6970- **Wire-format and ABI compatibility across host and device.**71 `DEPTHAI_SERIALIZE` / `DEPTHAI_SERIALIZE_EXT` field lists the72 `DatatypeEnum` order, and every `Properties` struct are the serialised73 contract between the host SDK and device firmware. Both sides compile the74 same header, but a host and a device of different versions talk to each75 other in the field.7677 Flag any of these in a shared type78 (`include/depthai/pipeline/datatype/`, `include/depthai/properties/`,79 `include/depthai/common/`):80 - a field reordered, renamed, retyped, or removed from a81 `DEPTHAI_SERIALIZE*` list;82 - a `DatatypeEnum` enumerator inserted in the middle, reordered, or83 removed. New values append at the end, before `COUNT`;84 - a new field with no default value.8586 Correct pattern: append the field at the end of the struct **and** at the87 end of the `DEPTHAI_SERIALIZE*` list, with a default initialiser.88 Severity: CRITICAL8990## B. Backward compatibility9192- **Every change must be backward compatible.**93 A new parameter needs a new overload, an optional, or a default value.94 Severity: CRITICAL9596- **Removal and renaming go through deprecation.**97 Keep the old symbol and mark it98 `[[deprecated("Use <replacement> instead")]]`. The message must name the99 replacement — that is the house pattern100 (`XLinkConnection::getMxId`, `ColorCamera::setCamId`, `PointCloudData::isSparse`).101 Deleting a public symbol outright is a break.102 Severity: CRITICAL103104## C. Build system105106- **C++17 is the hard target.**107 Flag all features that use C++20 or later.108 Severity: HIGH109110- **Formatting is enforced by CI, not by opinion.**111 `ci/check_format.sh <builddir>` fails on any diff after112 `--target clangformat`. Do not hand-format; do not fight the tool.113 Severity: MEDIUM114115## D. Adding a datatype (depthai-core)116117Two CI scripts encode this as a hard gate. A new or changed message must118satisfy all of it. Use the scripts as the checklist:119120`ci/check_datatype_enum_consistency.sh` requires:1211. The class lives in `include/depthai/pipeline/datatype/<Name>.hpp` and122 inherits `Buffer`.1232. `getDatatype()` returns `DatatypeEnum::<Name>`, and `<Name>` exists in124 `include/depthai/pipeline/datatype/DatatypeEnum.hpp` - appended, never125 inserted.1263. `<Name>` appears as a key **and** as a child entry in the hierarchy map in127 `src/pipeline/datatype/DatatypeEnum.cpp`.1284. `src/pipeline/datatype/StreamMessageParser.cpp` has a129 `case DatatypeEnum::<Name>: return parseDatatype<Name>(...)`.1305. `serialize(std::vector<std::uint8_t>&, DatatypeEnum&) const override` is131 implemented, and the class ends with132 `DEPTHAI_SERIALIZE(<Name>, Buffer::sequenceNum, Buffer::ts, Buffer::tsDevice, Buffer::tsSystem, <fields...>);`133134`ci/check_protobuf_consistency.sh` requires, if the message is protobuf135serialisable:1361376. A `.proto` in `protos/`, registered in `protos/CMakeLists.txt`.1387. `serializeProto` / `deserializeProto` / `serializeSchema` overrides inside139 `#ifdef DEPTHAI_ENABLE_PROTOBUF`, and the class also inherits140 `ProtoSerializable`.1418. `getProtoMessage(const <Name>*)` declared in `src/utility/ProtoSerialize.hpp`142 **and** defined in `src/utility/ProtoSerialize.cpp` — the two sets must143 match exactly.1449. If deserialisation is supported: `setProtoMessage(<Name>&)` in both files,145 a `schemaNameToDatatype` mapping, and the enum listed in146 `deserializationSupported`.147Severity: HIGH148149## E. Tests150151- **Every new node, message, feature, and bugfix needs a test.**152 The test must exercise the real behaviour, not just construct the object.153 Severity: HIGH154155- **Serialization roundtrip**156 Any change to a type deriving from `include/depthai/pipeline/datatype/Buffer.hpp` 157 needs a serialization roundtrip test that runs on both RVC2 and RVC4.**158 Severity: HIGH159160## F. Python bindings (depthai-core only)161162- **All public C++ API must be exposed to Python.** `depthai-device-kb` has163 no bindings, so this rule does not apply there.164165 A new public class needs166 `bindings/python/src/<mirrored path>/<Name>Bindings.cpp` with:167 - `void bind_<name>(pybind11::module& m, void* pCallstack)`,168 - all `py::class_` / `py::enum_` declarations first, then the169 callstack push/pop block, then the actual `.def(...)` bindings — this170 two-phase order is what makes forward references work;171 - `DOC(dai, <Name>)` on every class and method;172 - `PYBIND11_MAKE_OPAQUE(std::vector<dai::T>)` plus173 `py::bind_vector` and `py::implicitly_convertible<py::list, std::vector<T>>()`174 for any new vector type crossing the boundary.175176 Register the file in `bindings/python/CMakeLists.txt` and push its `bind`177 into the callstack.178 Severity: HIGH179180- **Doxygen comments are the Python docstrings.**181 `DOC(dai, X)` is generated from the header comment by `pybind11_mkdoc`. A182 missing or stale Doxygen comment silently ships an empty or wrong Python183 docstring. Every public function needs one:184 ```cpp185 /**186 * Set edges connections between keypoints.187 * @param edges Vector edges connections represented as pairs of keypoint indices.188 * @note This is only applicable if keypoints decoding is enabled.189 */190 void setKeypointEdges(const std::vector<dai::Edge>& edges);191 ```192 Severity: MEDIUM - raise to HIGH when the symbol is bound to Python.193194## G. Examples (depthai-core only)195196- **C++ and Python examples are mirrored.**197 `examples/cpp/<Category>/<snake_case>.cpp` must have a matching198 `examples/python/<Category>/<snake_case>.py`. A new C++ example without its199 Python twin is a finding, and the same the other way round. Register the200 C++ one with `dai_add_example`.201 Severity: MEDIUM202203## H. Node structure204205- **Host-side node (`depthai-core`).**206 ```cpp207 class ImageAlign : public DeviceNodeCRTP<DeviceNode, ImageAlign, ImageAlignProperties>208 public:209 constexpr static const char* NAME = "ImageAlign";210 using DeviceNodeCRTP::DeviceNodeCRTP;211 protected:212 Properties& getProperties() override;213 ```214 `Input` and `Output` members are declared inline with their queue config215 and accepted datatypes:216 `Input input{*this, {"input", DEFAULT_GROUP, false, 4, {{DatatypeEnum::ImgFrame, false}}}};`217 A pure host node derives from `CustomThreadedNode<T>` / `ThreadedHostNode`.218219- **Device-side node (`depthai-device-kb`).**220 Lives in `namespace dai { namespace gate {`, derives the core221 `dai::node::<X>`, and overrides `run()`, `buildStage1()`, and222 `runOnHost()`. Its `NAME` aliases the core node's `NAME`. A device node223 must also appear in `src/pipeline/PipelineBuilder.cpp`, otherwise the224 pipeline cannot instantiate it.225226- **Run loops use `while(mainLoop())`, not `while(isRunning())`.**227 `mainLoop()` also drives pipeline debugging and state reporting.228 Wrap a blocking input read in `auto blockEvent = this->inputBlockEvent();`229 and a blocking send in `outputBlockEvent()`, so the queue-blocking stats in230 `PipelineDebugging.md` stay correct.231 Severity: MEDIUM232233- **Setters return the node by reference for chaining**234 (`ImageAlign& setNumShaves(int numShaves);`) and write into `properties`.235 Severity: LOW236237## I. Reuse existing code238239New features and nodes must reuse what exists. Search before you add a240helper — `include/depthai/utility/` already holds `matrixOps.hpp`,241`span.hpp`, `Serialization.hpp`, `ImageManipImpl.hpp`, `LockingQueue.hpp`,242`CircularBuffer.hpp`, `Pimpl.hpp`, `RecordReplay.hpp`, `Clock.hpp`,243`Memory.hpp`, and more; `include/depthai/common/` holds the shared value244types. Cite the existing equivalent if one exists.245246For a genuinely new helper, judge where it belongs: node-agnostic logic, or247logic with a second caller in sight, belongs in `utility/` or `common/`;248anything tied to a node's internals stays local to that node. Do not promote249speculatively. Near-duplicate blocks across nodes are candidates for a common250version.251Severity: MEDIUM252253## J. Naming and style254255House style, confirmed across both repos. This overrides the general256guidelines in Part 2 where the two disagree.257258| Kind | Convention | Example |259| -------------------------------------- | ------------- | -------------------------------------- |260| Class, struct, enum, and its file name | `PascalCase` | `ImgFrame`, `ImageAlignProperties.hpp` |261| Function, method, variable, member | `camelCase` | `setNumShaves`, `alignWidth` |262| Enumerator | `ALL_CAPS` | `CameraBoardSocket::CAM_A` |263| Compile-time constant | `ALL_CAPS` | `DEFAULT_QUEUE_SIZE` |264| Namespace | lowercase | `dai`, `dai::node`, `dai::gate` |265Check every modified file, examples included.266Severity: MEDIUM267268# PART 2 — GENERAL C++ STANDARDS269270Derived from the C++ Core Guidelines. Rule IDs (R.11, ES.20, …) refer to271<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines> — cite them in272findings so the author can look up the rationale.273274## CRITICAL — Memory safety275276- Raw `new`/`delete` instead of `unique_ptr`/`shared_ptr` or RAII (R.11, R.20)277- `malloc`/`free` in C++ code (R.10)278- Buffer overflows: C arrays, `strcpy`, `sprintf` without bounds (SL.con.1)279- Use-after-free: dangling pointers, invalidated iterators280- Uninitialized variables read before assignment (ES.20)281- Missing null check before pointer dereference282- Returning a pointer or reference to a local (F.43)283- Resources not tied to object lifetime (P.8, E.6)284285## CRITICAL — Security286287- Command injection via unvalidated input to `system()` / `popen()`288- Format string attacks: user input as a `printf` or `fmt` format289- Unchecked integer arithmetic on untrusted input (ES.46, ES.100)290- Hardcoded secrets, API keys, passwords in source291- `reinterpret_cast` without documented justification (ES.48)292- Casting away `const` (ES.50)293294## HIGH — Concurrency295296- Data races: shared mutable state without synchronisation (CP.2, CP.3)297- Deadlocks: multiple mutexes taken in inconsistent order — use298 `std::scoped_lock` (CP.21)299- Manual `lock()`/`unlock()` instead of RAII guards (CP.20)300- Unnamed lock guards — `std::lock_guard<std::mutex>(m);` destroys immediately301 (CP.44)302- Detached threads without lifetime management (CP.26)303- Waiting on a condition variable without a predicate (CP.42)304- Calling unknown code (callbacks) while holding a lock (CP.22)305- `volatile` used for synchronisation (CP.8)306- Node-specific: blocking on an input queue outside a `mainLoop()` iteration,307 or holding a lock across a queue `get()` — the node cannot then be stopped.308309## HIGH — Class design and code quality310311- Rule of Five violated: some special members defined, others missing (C.21)312- Special members defined where Rule of Zero would do (C.20)313- Base class destructor neither public-virtual nor protected-non-virtual (C.35)314- Single-argument constructor not `explicit` (C.46)315- Virtual functions without exactly one of `virtual`/`override`/`final` (C.128)316- Virtual calls in constructors or destructors (C.82)317- `memset`/`memcpy` on non-trivial types (C.90)318- Missing `const` correctness on methods, parameters, references (Con.2, Con.3)319- Functions over ~50 lines or doing more than one thing (F.2, F.3)320- Nesting deeper than 4 levels321- C-style code: `typedef` over `using` (T.43), C arrays, C-style casts (ES.48)322- Non-const globals (I.2)323- Ownership transferred by raw pointer or reference (I.11, R.3)324325## MEDIUM — Performance326327- Large objects passed by value where `const&` is right (F.16)328- Missing `std::move` on sink parameters329- Missing `reserve()` on known-size containers330- String concatenation in loops331- Compile-time-computable work left at runtime (Per.11)332- Pointer-chasing layouts where contiguous storage would do (Per.19)333- Optimisation claims without measurement (Per.6) — flag both unmeasured334 optimisation and premature complexity335- Copying an `ImgFrame` payload where a `span` or shared `Memory` would do336337## MEDIUM — Idiom and hygiene338339- Not `const`/`constexpr` by default (Con.1, ES.25)340- `0`/`NULL` instead of `nullptr` (ES.47)341- Narrowing or signed/unsigned mixed arithmetic (ES.46, ES.100)342- `using namespace` at global scope in a header (SF.7)343- Headers not self-contained (SF.8)344- `std::endl` instead of `'\n'` (SL.io.50)345- Output parameters where a returned struct is clearer (F.20, F.21)346- Exceptions: built-in types thrown, caught by value, empty catch blocks,347 exceptions used for flow control (E.14, E.15, E.3)348349---350351# Output format352353````354# C++ Review355356## Scope357<repo, files reviewed, commit range or PR>358359## Static analysis360clang-format-18: <clean | n files would change>361clang-tidy-18: <n> findings (<n> actionable)362datatype consistency: <PASS | FAIL | n/a>363protobuf consistency: <PASS | FAIL | n/a>364build: <clean | n warnings>365366## Findings367368### [CRITICAL] <one-line title> (PROJECT: <rule name> | <Core Guideline ID>)369`path/to/file.cpp:45`370371<one or two sentences: what's wrong and what goes wrong because of it>372373Current:374```cpp375<minimal excerpt>376```377378Suggested:379```cpp380<the fix>381```382383### [HIGH] ...384### [MEDIUM] ...385### [INFO] ...386387## Checked and clean388<one line each: what you verified and found correct>389390## Summary391CRITICAL: n HIGH: n MEDIUM: n INFO: n392Verdict: APPROVE | WARN | BLOCK393````394395## Verdict rules396397| Verdict | Condition |398| ----------- | -------------------------------------------- |399| **APPROVE** | No CRITICAL or HIGH findings |400| **WARN** | MEDIUM findings only — merge with judgement |401| **BLOCK** | Any CRITICAL or HIGH finding |402403Any violation of a Part 1 project rule marked CRITICAL blocks on its own,404regardless of what Part 2 turns up.405406## Reviewing discipline407408- Every finding needs a file and line. No findings without a location.409- One finding per problem. Don't restate the same issue per call site — cite410 the first and note the count.411- Suggest a fix, don't just name the rule.412- Say what you checked and found clean, briefly. A review that only lists413 problems hides its own coverage gaps.414- If a change is correct but the surrounding design makes it fragile, say so415 under INFO rather than inflating the severity.416- Don't flag anything listed under "Known exceptions".417- State which repo you reviewed. A rule from the wrong repo is a false418 positive.