Skip to content

Commit 83368c3

Browse files
authored
Merge pull request #359 from MoonModules/ai_instructions_update
sync AI instructions with upstream
2 parents 6999737 + c383937 commit 83368c3

2 files changed

Lines changed: 68 additions & 29 deletions

File tree

.github/copilot-instructions.md

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,25 +88,50 @@ docs/ # Contributor docs: coding guidelines and design doc
8888
- **Repository language is English.** Suggest translations for non-English content.
8989
- **Use VS Code with PlatformIO extension** for best development experience.
9090
- **Never edit or commit** `wled00/html_*.h` and `wled00/js_*.h` — auto-generated from `wled00/data/`.
91-
- If updating Web UI files in `wled00/data/`, **make use of common functions in `wled00/data/common.js` whenever possible**.
9291
- **When unsure, say so.** Gather more information rather than guessing.
93-
- **Acknowledge good patterns** when you see them. Summarize good practices as part of your review - positive feedback always helps.
92+
- **Acknowledge good patterns** when you see them. Positive feedback always helps.
9493
- **Provide references** when making analyses or recommendations. Base them on the correct branch or PR.
9594
- **Highlight user-visible breaking changes and ripple effects**. Ask for confirmation that these were introduced intentionally.
9695
- **Unused / dead code must be justified or removed**. This helps to keep the codebase clean, maintainable and readable.
9796
- **C++ formatting available**: `clang-format` is installed but not in CI
9897
- No automated linting is configured — match existing code style in files you edit.
9998

100-
See `docs/cpp.instructions.md`, `docs/esp-idf.instructions.md` and `docs/web.instructions.md` for language-specific conventions, and `docs/cicd.instructions.md` for GitHub Actions workflows.
99+
Refer to `docs/cpp.instructions.md`, `docs/esp-idf.instructions.md` and `docs/web.instructions.md` for language-specific conventions, and `docs/cicd.instructions.md` for GitHub Actions workflows.
100+
101+
### Feature Flags
102+
- **Verify feature-flag names.** Every `WLED_ENABLE_*` / `WLED_DISABLE_*` flag must exactly match one of the names below — misspellings are silently ignored by the preprocessor (e.g. `WLED_IR_DISABLE` instead of `WLED_DISABLE_INFRARED`), causing silent build variations. Flag unrecognised names as likely typos and suggest the correct spelling.
103+
104+
**`WLED_DISABLE_*`**: `2D`, `ADALIGHT`, `ALEXA`, `BROWNOUT_DET`, `ESPNOW`, `FILESYSTEM`, `HUESYNC`, `IMPROV_WIFISCAN`, `INFRARED`, `LOXONE`, `MQTT`, `OTA`, `PARTICLESYSTEM1D`, `PARTICLESYSTEM2D`, `PIXELFORGE`, `WEBSOCKETS`
105+
106+
**`WLED_ENABLE_*`**: `ADALIGHT`, `AOTA`, `DMX`, `DMX_INPUT`, `DMX_OUTPUT`, `FS_EDITOR`, `GIF`, `HUB75MATRIX`, `JSONLIVE`, `LOXONE`, `MQTT`, `PIXART`, `PXMAGIC`, `USERMOD_PAGE`, `WEBSOCKETS`, `WPA_ENTERPRISE`
107+
108+
<!-- HUMAN_ONLY_START -->
109+
```cpp
110+
#ifdef WLED_DMX_ENABLED // wrong flag - initialization silently skipped
111+
initDMX();
112+
#endif
113+
114+
#ifdef WLED_ENABLE_DMX // correct flag - initialization performed only when the build supports DMX
115+
initDMX();
116+
#endif
117+
```
118+
<!-- HUMAN_ONLY_END -->
119+
101120

102121
### Attribution for AI-generated code
103122
Using AI-generated code can hide the source of the inspiration / knowledge / sources it used.
104123
- Document attribution of inspiration / knowledge / sources used in the code, e.g. link to GitHub repositories or other websites describing the principles / algorithms used.
105-
- When a larger block of code is generated by an AI tool, mark it with an `// AI: below section was generated by an AI` comment (see C++ guidelines).
124+
- When a larger block of code is generated by an AI tool, embed it into `// AI: below section was generated by an AI` ... `// AI: end` comments (see C++ guidelines).
106125
- Every non-trivial AI-generated function should have a brief comment describing what it does. Explain parameters when their names alone are not self-explanatory.
107126
- AI-generated code must be well documented with meaningful comments that explain intent, assumptions, and non-obvious logic. Do not rephrase source code; explain concepts and reasoning.
108127

109128
### Pull Request Expectations
110129

111130
- **No force-push on open PRs.** Once a pull request is open and being reviewed, do not force-push (`git push --force`) to the branch. Force-pushing rewrites history that reviewers may have already commented on, making it impossible to track incremental changes. Use regular commits or `git merge` to incorporate feedback; the branch will be squash-merged when it is accepted.
131+
- **Modifications to ``platformio.ini`` MUST be approved explicitly** by a *maintainer* or *WLED organisation Member*. Modifications to the global build environment may break github action builds. Always flag them.
112132
- **Document your changes in the PR.** Every pull request should include a clear description of *what* changed and *why*. If the change affects user-visible behavior, describe the expected impact. Link to related issues where applicable. Provide screenshots to showcase new features.
133+
134+
### Supporting Reviews and Discussions
135+
- **For "is it worth doing?" debates** about proposed reliability, safety, or data-integrity mechanisms (CRC checks, backups, power-loss protection): suggest a software **FMEA** (Failure Mode and Effects Analysis).
136+
Clarify the main feared events, enumerate failure modes, assess each mitigation's effectiveness per failure mode, note common-cause failures, and rate credibility for the typical WLED use case.
137+

docs/cpp.instructions.md

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,16 @@ See also: [CONTRIBUTING.md](../CONTRIBUTING.md) for general style guidelines tha
2525

2626
- **camelCase** for functions and variables: `setValuesFromMainSeg()`, `effectCurrent`
2727
- **PascalCase** for classes and structs: `PinManagerClass`, `BusConfig`
28+
- **PascalCase** for enum values: `PinOwner::BusDigital`
2829
- **UPPER_CASE** for macros and constants: `WLED_MAX_USERMODS`, `DEFAULT_CLIENT_SSID`
2930

31+
## General
32+
33+
- Follow the existing style in the file you are editing
34+
- If possible, use `static` for local (C-style) variables and functions (keeps the global namespace clean)
35+
- Avoid unexplained "magic numbers". Prefer named constants (`constexpr`) or C-style `#define` constants for repeated numbers that have the same meaning
36+
- Include `"wled.h"` as the primary project header where needed
37+
3038
<!-- HUMAN_ONLY_START -->
3139
## Header Guards
3240

@@ -61,7 +69,7 @@ Most headers use `#ifndef` / `#define` guards. Some newer headers add `#pragma o
6169
void calculateCRC(const uint8_t* data, size_t len) {
6270
...
6371
}
64-
// AI: end of AI-generated section
72+
// AI: end
6573
```
6674
6775
Single-line AI-assisted edits do not need the marker — use it when the AI produced a contiguous block that a human did not write line-by-line.
@@ -142,25 +150,28 @@ Heap fragmentation is a concern:
142150
<!-- HUMAN_ONLY_END -->
143151

144152
## `const` and `constexpr`
145-
Add `const` to cached locals in hot-path code (helps the compiler keep values in registers). Pass and store objects by `const&` to avoid copies in loops.
146-
147153
<!-- HUMAN_ONLY_START -->
148154
`const` is a promise to the compiler that a value (or object) will not change - a function declared with a `const char* message` parameter is not allowed to modify the content of `message`.
149155
This pattern enables optimizations and makes intent clear to reviewers.
150156

151-
### `const` locals
157+
`constexpr` allows to define constants that are *guaranteed* to be evaluated by the compiler (zero run-time costs).
158+
159+
<!-- HUMAN_ONLY_END -->
160+
- For function parameters that are read-only, prefer `const &` or `const`.
152161

162+
### `const` locals
163+
<!-- HUMAN_ONLY_START -->
153164
* Adding `const` to a local variable that is only assigned once is optional, but *not* strictly necessary.
154-
* In hot-path code, `const` on cached locals may help the compiler keep values in registers:
165+
<!-- HUMAN_ONLY_END -->
166+
* In hot-path code, `const` on cached locals may help the compiler keep values in registers.
155167
```cpp
156168
const uint_fast16_t cols = vWidth();
157169
const uint_fast16_t rows = vHeight();
158170
```
159171

160-
<!-- HUMAN_ONLY_END -->
161172
### `const` references to avoid copies
162-
163-
Pass and store objects by `const &` (or `&`) instead of copying them implicitly. This avoids constructing temporary objects on every access — especially important in loops.
173+
- Pass objects by `const &` (or `&`) instead of copying them implicitly.
174+
- Use `const &` (or `&`) inside loops - This avoids constructing temporary objects on every access.
164175

165176
<!-- HUMAN_ONLY_START -->
166177
```cpp
@@ -174,11 +185,14 @@ For function parameters that are read-only, prefer `const &`:
174185
BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com);
175186
```
176187
<!-- HUMAN_ONLY_END -->
188+
- Class **Data Members:** Avoid reference data members (`T&` or `const T&`) in a class.
189+
A reference member can outlive the object it refers to, causing **dangling reference** bugs that are hard to diagnose. Prefer value storage or use a pointer and document the expected lifetime.
177190
178-
### `constexpr` over `#define`
179191
<!-- HUMAN_ONLY_START -->
192+
<!-- hidden from AI for now - codebase is not compliant to this rule (slowly migrating) -->
193+
### `constexpr` over `#define`
180194
181-
Prefer `constexpr` for compile-time constants. Unlike `#define`, `constexpr` respects scope and type safety, keeping the global namespace clean:
195+
- Prefer `constexpr` for compile-time constants. Unlike `#define`, `constexpr` respects scope and type safety, keeping the global namespace clean.
182196
183197
```cpp
184198
// Prefer:
@@ -190,11 +204,14 @@ constexpr int WLED_MAX_BUSSES = WLED_MAX_DIGITAL_CHANNELS + WLED_MAX_ANALOG_CHAN
190204
```
191205

192206
Note: `#define` is still needed for conditional compilation guards (`#ifdef`), platform macros, and values that must be overridable from build flags.
207+
<!-- HUMAN_ONLY_END -->
193208

194209
### `static_assert` over `#error`
195210

196-
Use `static_assert` instead of the C-style `#if … #error … #endif` pattern when validating compile-time constants. It provides a clear message and works with `constexpr` values:
211+
- Use `static_assert` instead of the C-style `#if … #error … #endif` pattern when validating compile-time constants. It provides a clear message and works with `constexpr` values.
212+
- `#define` and `#if ... #else ... #endif` is still needed for conditional-compilation guards and build-flag-overridable values.
197213

214+
<!-- HUMAN_ONLY_START -->
198215
```cpp
199216
// Prefer:
200217
constexpr int WLED_MAX_BUSSES = WLED_MAX_DIGITAL_CHANNELS + WLED_MAX_ANALOG_CHANNELS;
@@ -212,10 +229,6 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit");
212229
"PinOwner::None must be zero, so default array initialization works as expected");
213230
```
214231
<!-- HUMAN_ONLY_END -->
215-
216-
Prefer `constexpr` over `#define` for typed constants (scope-safe, debuggable). Use `static_assert` instead of `#if … #error` for compile-time validation.
217-
Exception: `#define` is required for conditional-compilation guards and build-flag-overridable values.
218-
219232
### `static` and `const` class methods
220233
221234
#### `const` member functions
@@ -425,7 +438,7 @@ Move invariant calculations before the loop. Pre-compute reciprocals to replace
425438
```cpp
426439
const uint_fast16_t cols = virtualWidth();
427440
const uint_fast16_t rows = virtualHeight();
428-
uint_fast8_t fadeRate = (255 - rate) >> 1;
441+
uint_fast8_t fadeRate = (255U - rate) >> 1;
429442
float mappedRate_r = 1.0f / (float(fadeRate) + 1.1f); // reciprocal — avoid division inside loop
430443
```
431444

@@ -441,13 +454,14 @@ uint32_t wg = (((c1 >> 8) & TWO_CHANNEL_MASK) * amount) & ~TWO_CHANNEL_MASK;
441454
return rb | wg;
442455
```
443456

444-
### Bit Shifts Over Division (mainly for RISC-V boards)
457+
### Bit Shifts Over Division (mainly for RISC-V and ESP8266 boards)
445458

446459
ESP32 and ESP32-S3 (Xtensa core) have a fast "integer divide" instruction, so manual shifts rarely help.
447-
On RISC-V targets (ESP32-C3/C6/P4), prefer explicit bit-shifts for power-of-two arithmetic — the compiler does **not** always convert divisions to shifts on RISC-V at `-O2`. Always use unsigned operands; signed right-shift is implementation-defined.
460+
On RISC-V targets (ESP32-C3/C6/P4) and ESP8266, prefer explicit bit-shifts for power-of-two arithmetic — the compiler does **not** always convert divisions to shifts.
461+
Always use unsigned operands for right shifts; signed right-shift is implementation-defined.
448462

449463
<!-- HUMAN_ONLY_START -->
450-
On RISC-V-based boards (ESP32-C3, ESP32-C6, ESP32-C5) explicit shifts can be beneficial.
464+
Explicit shifts can be beneficial on RISC-V-based boards (ESP32-C3, ESP32-C6, ESP32-C5) and on ESP8266 boards.
451465
```cpp
452466
position >> 3 // instead of position / 8
453467
(255U - rate) >> 1 // instead of (255 - rate) / 2
@@ -488,6 +502,9 @@ if (lastKelvin != kelvin) {
488502
```
489503

490504
<!-- HUMAN_ONLY_END -->
505+
506+
---
507+
491508
## Multi-Task Synchronization
492509

493510
ESP32 runs multiple FreeRTOS tasks concurrently (e.g. network handling, LED output, JSON parsing). Use the WLED-MM mutex macros for synchronization — they expand to FreeRTOS recursive semaphore calls on ESP32 and compile to no-ops on ESP8266:
@@ -525,7 +542,7 @@ Always pair every `esp32SemTake` with a matching `esp32SemGive`. Choose a timeou
525542
<!-- HUMAN_ONLY_START -->
526543
* On ESP32, `delay(ms)` calls `vTaskDelay(ms / portTICK_PERIOD_MS)`, which **suspends only the calling task**. The FreeRTOS scheduler immediately runs all other ready tasks.
527544
* The Arduino `loop()` function runs inside `loopTask`. Calling `delay()` there does *not* block the network stack, audio FFT, LED DMA, nor any other FreeRTOS task.
528-
* This differs from ESP8266, where `delay()` stalled the entire system unless `yield()` was called inside.
545+
* This differs from ESP8266, where `delay()` stalls the entire system unless `yield()` was called inside.
529546
<!-- HUMAN_ONLY_END -->
530547

531548
- On ESP32, `delay()` is generally allowed, as it helps to efficiently manage CPU usage of all tasks.
@@ -565,12 +582,9 @@ void myTask(void*) {
565582
- Prefer blocking FreeRTOS primitives (`xQueueReceive`, `ulTaskNotifyTake`, `vTaskDelayUntil`) over `delay(1)` polling where precise timing or event-driven behaviour is needed.
566583
- **Watchdog note.** WLED-MM disables the Task Watchdog by default (`WLED_WATCHDOG_TIMEOUT 0` in `wled.h`). When enabled, `esp_task_wdt_reset()` is called at the end of each `loop()` iteration. Long blocking operations inside `loop()` — such as OTA downloads or slow file I/O — must call `esp_task_wdt_reset()` periodically, or be restructured so the main loop is not blocked for longer than the configured timeout.
567584

568-
## General
585+
## Caveats and Pitfalls
569586

570-
- Follow the existing style in the file you are editing
571-
- If possible, use `static` for local (C-style) variables and functions (keeps the global namespace clean)
572-
- Avoid unexplained "magic numbers". Prefer named constants (`constexpr`) or C-style `#define` constants for repeated numbers that have the same meaning
573-
- Include `"wled.h"` as the primary project header where needed
587+
- **LittleFS filenames**: File paths passed to `file.open()` must not exceed 255 bytes (`LFS_NAME_MAX`). Validate constructed paths (e.g., `/ledmap_` + segment name + `.json`) stay within this limit (assume standard configurations, like WLED_MAX_SEGNAME_LEN = 64).
574588

575589
- **Float-to-unsigned conversion is undefined behavior when the value is out of range.** Converting a negative `float` directly to an unsigned integer type (`uint8_t`, `uint16_t`, …) is UB per the C++ standard — the Xtensa (ESP32) toolchain may silently wrap, but RISC-V (ESP32-C3/C5/C6/P4) can produce different results due to clamping. Cast through a signed integer first:
576590
```cpp

0 commit comments

Comments
 (0)