red64-cli 0.3.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +194 -338
  2. package/dist/cli/parseArgs.d.ts.map +1 -1
  3. package/dist/cli/parseArgs.js +5 -13
  4. package/dist/cli/parseArgs.js.map +1 -1
  5. package/dist/components/init/types.d.ts +0 -2
  6. package/dist/components/init/types.d.ts.map +1 -1
  7. package/dist/components/screens/HelpScreen.d.ts.map +1 -1
  8. package/dist/components/screens/HelpScreen.js +0 -2
  9. package/dist/components/screens/HelpScreen.js.map +1 -1
  10. package/dist/components/screens/InitScreen.d.ts.map +1 -1
  11. package/dist/components/screens/InitScreen.js +5 -8
  12. package/dist/components/screens/InitScreen.js.map +1 -1
  13. package/dist/components/screens/StartScreen.d.ts.map +1 -1
  14. package/dist/components/screens/StartScreen.js +29 -8
  15. package/dist/components/screens/StartScreen.js.map +1 -1
  16. package/dist/components/screens/StatusScreen.d.ts.map +1 -1
  17. package/dist/components/screens/StatusScreen.js +16 -1
  18. package/dist/components/screens/StatusScreen.js.map +1 -1
  19. package/dist/services/AgentInvoker.d.ts.map +1 -1
  20. package/dist/services/AgentInvoker.js +76 -37
  21. package/dist/services/AgentInvoker.js.map +1 -1
  22. package/dist/services/ClaudeErrorDetector.d.ts +1 -1
  23. package/dist/services/ClaudeErrorDetector.d.ts.map +1 -1
  24. package/dist/services/ClaudeErrorDetector.js +1 -0
  25. package/dist/services/ClaudeErrorDetector.js.map +1 -1
  26. package/dist/services/ClaudeHealthCheck.d.ts +7 -0
  27. package/dist/services/ClaudeHealthCheck.d.ts.map +1 -1
  28. package/dist/services/ClaudeHealthCheck.js +76 -12
  29. package/dist/services/ClaudeHealthCheck.js.map +1 -1
  30. package/dist/services/ConfigService.d.ts +1 -0
  31. package/dist/services/ConfigService.d.ts.map +1 -1
  32. package/dist/services/ConfigService.js.map +1 -1
  33. package/dist/services/DockerRunner.js +1 -1
  34. package/dist/services/DockerRunner.js.map +1 -1
  35. package/dist/services/PhaseExecutor.d.ts.map +1 -1
  36. package/dist/services/PhaseExecutor.js +2 -1
  37. package/dist/services/PhaseExecutor.js.map +1 -1
  38. package/dist/services/TaskRunner.d.ts.map +1 -1
  39. package/dist/services/TaskRunner.js +2 -1
  40. package/dist/services/TaskRunner.js.map +1 -1
  41. package/dist/services/index.d.ts +1 -1
  42. package/dist/services/index.d.ts.map +1 -1
  43. package/dist/services/index.js +1 -1
  44. package/dist/services/index.js.map +1 -1
  45. package/dist/types/index.d.ts +4 -3
  46. package/dist/types/index.d.ts.map +1 -1
  47. package/dist/types/index.js.map +1 -1
  48. package/framework/stacks/c/code-quality.md +326 -0
  49. package/framework/stacks/c/coding-style.md +347 -0
  50. package/framework/stacks/c/conventions.md +513 -0
  51. package/framework/stacks/c/error-handling.md +350 -0
  52. package/framework/stacks/c/feedback.md +158 -0
  53. package/framework/stacks/c/memory-safety.md +408 -0
  54. package/framework/stacks/c/tech.md +122 -0
  55. package/framework/stacks/c/testing.md +472 -0
  56. package/framework/stacks/cpp/code-quality.md +282 -0
  57. package/framework/stacks/cpp/coding-style.md +363 -0
  58. package/framework/stacks/cpp/conventions.md +420 -0
  59. package/framework/stacks/cpp/error-handling.md +264 -0
  60. package/framework/stacks/cpp/feedback.md +104 -0
  61. package/framework/stacks/cpp/memory-safety.md +351 -0
  62. package/framework/stacks/cpp/tech.md +160 -0
  63. package/framework/stacks/cpp/testing.md +323 -0
  64. package/framework/stacks/java/code-quality.md +357 -0
  65. package/framework/stacks/java/coding-style.md +400 -0
  66. package/framework/stacks/java/conventions.md +437 -0
  67. package/framework/stacks/java/error-handling.md +408 -0
  68. package/framework/stacks/java/feedback.md +180 -0
  69. package/framework/stacks/java/tech.md +126 -0
  70. package/framework/stacks/java/testing.md +485 -0
  71. package/framework/stacks/javascript/async-patterns.md +216 -0
  72. package/framework/stacks/javascript/code-quality.md +182 -0
  73. package/framework/stacks/javascript/coding-style.md +293 -0
  74. package/framework/stacks/javascript/conventions.md +268 -0
  75. package/framework/stacks/javascript/error-handling.md +216 -0
  76. package/framework/stacks/javascript/feedback.md +80 -0
  77. package/framework/stacks/javascript/tech.md +114 -0
  78. package/framework/stacks/javascript/testing.md +209 -0
  79. package/framework/stacks/loco/code-quality.md +156 -0
  80. package/framework/stacks/loco/coding-style.md +247 -0
  81. package/framework/stacks/loco/error-handling.md +225 -0
  82. package/framework/stacks/loco/feedback.md +35 -0
  83. package/framework/stacks/loco/loco.md +342 -0
  84. package/framework/stacks/loco/structure.md +193 -0
  85. package/framework/stacks/loco/tech.md +129 -0
  86. package/framework/stacks/loco/testing.md +211 -0
  87. package/framework/stacks/rust/code-quality.md +370 -0
  88. package/framework/stacks/rust/coding-style.md +475 -0
  89. package/framework/stacks/rust/conventions.md +430 -0
  90. package/framework/stacks/rust/error-handling.md +399 -0
  91. package/framework/stacks/rust/feedback.md +152 -0
  92. package/framework/stacks/rust/memory-safety.md +398 -0
  93. package/framework/stacks/rust/tech.md +121 -0
  94. package/framework/stacks/rust/testing.md +528 -0
  95. package/package.json +14 -2
@@ -0,0 +1,350 @@
1
+ # Error Handling Patterns
2
+
3
+ Structured error handling for C projects using return codes, errno, and the goto cleanup pattern for safe resource management.
4
+
5
+ ---
6
+
7
+ ## Philosophy
8
+
9
+ - **Return codes as the primary pattern**: Functions return `0` for success, negative values for errors
10
+ - **Fail fast**: Validate inputs early, return errors immediately on invalid state
11
+ - **Resource safety via goto cleanup**: A single cleanup label per function ensures all resources are freed
12
+ - **Make errors visible**: Every call that can fail must have its return value checked
13
+ - **Ref**: CERT C ERR00-C through ERR06-C, SEI CERT Secure Coding
14
+
15
+ ---
16
+
17
+ ## Return Code Conventions
18
+
19
+ ### Standard Return Pattern
20
+
21
+ | Return Value | Meaning |
22
+ |---|---|
23
+ | `0` | Success |
24
+ | `-1` or negative | Error (specific codes for specific errors) |
25
+ | Positive | Context-dependent (e.g., byte count, item count) |
26
+
27
+ ### Error Code Enum
28
+
29
+ ```c
30
+ /* GOOD: Centralized error codes */
31
+ typedef enum {
32
+ ERR_OK = 0,
33
+ ERR_NULL_PARAM = -1,
34
+ ERR_NOMEM = -2,
35
+ ERR_NOT_FOUND = -3,
36
+ ERR_ALREADY_EXISTS = -4,
37
+ ERR_VALIDATION = -5,
38
+ ERR_IO = -6,
39
+ ERR_TIMEOUT = -7,
40
+ ERR_INTERNAL = -8,
41
+ } error_code_t;
42
+
43
+ /* GOOD: Human-readable error strings */
44
+ const char *error_string(error_code_t code) {
45
+ switch (code) {
46
+ case ERR_OK: return "success";
47
+ case ERR_NULL_PARAM: return "null parameter";
48
+ case ERR_NOMEM: return "out of memory";
49
+ case ERR_NOT_FOUND: return "not found";
50
+ case ERR_ALREADY_EXISTS: return "already exists";
51
+ case ERR_VALIDATION: return "validation failed";
52
+ case ERR_IO: return "I/O error";
53
+ case ERR_TIMEOUT: return "timeout";
54
+ case ERR_INTERNAL: return "internal error";
55
+ default: return "unknown error";
56
+ }
57
+ }
58
+ ```
59
+
60
+ ---
61
+
62
+ ## The goto Cleanup Pattern
63
+
64
+ The most important error-handling pattern in C. A single `cleanup` label at the end of the function ensures every allocated resource is freed, regardless of which step failed.
65
+
66
+ ### GOOD: goto Cleanup
67
+
68
+ ```c
69
+ int process_file(const char *path, result_t *out) {
70
+ int rc = ERR_OK;
71
+ FILE *fp = NULL;
72
+ char *buffer = NULL;
73
+ cJSON *json = NULL;
74
+
75
+ if (!path || !out) {
76
+ return ERR_NULL_PARAM;
77
+ }
78
+
79
+ fp = fopen(path, "r");
80
+ if (!fp) {
81
+ rc = ERR_IO;
82
+ goto cleanup;
83
+ }
84
+
85
+ buffer = malloc(MAX_FILE_SIZE);
86
+ if (!buffer) {
87
+ rc = ERR_NOMEM;
88
+ goto cleanup;
89
+ }
90
+
91
+ size_t bytes = fread(buffer, 1, MAX_FILE_SIZE - 1, fp);
92
+ buffer[bytes] = '\0';
93
+
94
+ json = cJSON_Parse(buffer);
95
+ if (!json) {
96
+ rc = ERR_VALIDATION;
97
+ goto cleanup;
98
+ }
99
+
100
+ rc = extract_result(json, out);
101
+
102
+ cleanup:
103
+ if (json) cJSON_Delete(json);
104
+ if (buffer) free(buffer);
105
+ if (fp) fclose(fp);
106
+ return rc;
107
+ }
108
+ ```
109
+
110
+ ### BAD: Nested Ifs (The Pyramid of Doom)
111
+
112
+ ```c
113
+ /* BAD: Deeply nested, easy to miss a free, hard to maintain */
114
+ int process_file(const char *path, result_t *out) {
115
+ if (path && out) {
116
+ FILE *fp = fopen(path, "r");
117
+ if (fp) {
118
+ char *buffer = malloc(MAX_FILE_SIZE);
119
+ if (buffer) {
120
+ size_t bytes = fread(buffer, 1, MAX_FILE_SIZE - 1, fp);
121
+ buffer[bytes] = '\0';
122
+ cJSON *json = cJSON_Parse(buffer);
123
+ if (json) {
124
+ int rc = extract_result(json, out);
125
+ cJSON_Delete(json);
126
+ free(buffer);
127
+ fclose(fp);
128
+ return rc;
129
+ }
130
+ free(buffer);
131
+ }
132
+ fclose(fp);
133
+ }
134
+ return ERR_IO;
135
+ }
136
+ return ERR_NULL_PARAM;
137
+ }
138
+ ```
139
+
140
+ ### BAD: Multiple Return Points with Duplicated Cleanup
141
+
142
+ ```c
143
+ /* BAD: Cleanup code duplicated at every error point */
144
+ int process_file(const char *path, result_t *out) {
145
+ FILE *fp = fopen(path, "r");
146
+ if (!fp) return ERR_IO;
147
+
148
+ char *buffer = malloc(MAX_FILE_SIZE);
149
+ if (!buffer) {
150
+ fclose(fp); /* Must remember to free fp here */
151
+ return ERR_NOMEM;
152
+ }
153
+
154
+ cJSON *json = cJSON_Parse(buffer);
155
+ if (!json) {
156
+ free(buffer); /* Must free buffer AND fp */
157
+ fclose(fp);
158
+ return ERR_VALIDATION;
159
+ }
160
+
161
+ /* ... more code, more duplicated cleanup ... */
162
+ }
163
+ ```
164
+
165
+ ---
166
+
167
+ ## errno for System Calls
168
+
169
+ ```c
170
+ #include <errno.h>
171
+ #include <string.h>
172
+
173
+ /* GOOD: Check errno after system calls that set it */
174
+ int read_file(const char *path, char *buf, size_t buf_size) {
175
+ FILE *fp = fopen(path, "r");
176
+ if (!fp) {
177
+ log_error("fopen failed: %s (errno=%d)", strerror(errno), errno);
178
+ return ERR_IO;
179
+ }
180
+
181
+ size_t n = fread(buf, 1, buf_size - 1, fp);
182
+ if (ferror(fp)) {
183
+ log_error("fread failed: %s", strerror(errno));
184
+ fclose(fp);
185
+ return ERR_IO;
186
+ }
187
+
188
+ buf[n] = '\0';
189
+ fclose(fp);
190
+ return ERR_OK;
191
+ }
192
+
193
+ /* GOOD: Save errno before calling other functions that may overwrite it */
194
+ int safe_open(const char *path) {
195
+ int fd = open(path, O_RDONLY);
196
+ if (fd < 0) {
197
+ int saved_errno = errno; /* Save before log call */
198
+ log_error("open(%s) failed: %s", path, strerror(saved_errno));
199
+ errno = saved_errno; /* Restore for caller */
200
+ return -1;
201
+ }
202
+ return fd;
203
+ }
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Error Propagation Macros
209
+
210
+ ```c
211
+ /* GOOD: Propagate errors with a macro to reduce boilerplate */
212
+ #define RETURN_IF_ERROR(expr) \
213
+ do { \
214
+ int _rc = (expr); \
215
+ if (_rc != ERR_OK) { \
216
+ return _rc; \
217
+ } \
218
+ } while (0)
219
+
220
+ #define GOTO_IF_ERROR(expr, label) \
221
+ do { \
222
+ rc = (expr); \
223
+ if (rc != ERR_OK) { \
224
+ goto label; \
225
+ } \
226
+ } while (0)
227
+
228
+ /* Usage */
229
+ int init_system(config_t *cfg) {
230
+ RETURN_IF_ERROR(config_load(cfg));
231
+ RETURN_IF_ERROR(logger_init(cfg->log_level));
232
+ RETURN_IF_ERROR(database_connect(cfg->db_url));
233
+ return ERR_OK;
234
+ }
235
+
236
+ int process_request(const request_t *req, response_t *resp) {
237
+ int rc = ERR_OK;
238
+ char *buffer = NULL;
239
+ db_conn_t *conn = NULL;
240
+
241
+ buffer = malloc(BUFFER_SIZE);
242
+ if (!buffer) { rc = ERR_NOMEM; goto cleanup; }
243
+
244
+ conn = db_pool_acquire();
245
+ if (!conn) { rc = ERR_INTERNAL; goto cleanup; }
246
+
247
+ GOTO_IF_ERROR(validate_request(req), cleanup);
248
+ GOTO_IF_ERROR(execute_query(conn, req, buffer, BUFFER_SIZE), cleanup);
249
+ GOTO_IF_ERROR(build_response(buffer, resp), cleanup);
250
+
251
+ cleanup:
252
+ if (conn) db_pool_release(conn);
253
+ if (buffer) free(buffer);
254
+ return rc;
255
+ }
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Error Logging
261
+
262
+ ```c
263
+ /* GOOD: Log with context at the point of failure */
264
+ #define LOG_ERROR(fmt, ...) \
265
+ fprintf(stderr, "[ERROR] %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
266
+
267
+ #define LOG_WARN(fmt, ...) \
268
+ fprintf(stderr, "[WARN] %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
269
+
270
+ /* Usage */
271
+ int connect_to_server(const char *host, int port) {
272
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
273
+ if (fd < 0) {
274
+ LOG_ERROR("socket() failed: %s", strerror(errno));
275
+ return ERR_IO;
276
+ }
277
+
278
+ struct sockaddr_in addr = {0};
279
+ addr.sin_family = AF_INET;
280
+ addr.sin_port = htons((uint16_t)port);
281
+
282
+ if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) {
283
+ LOG_ERROR("invalid address: %s", host);
284
+ close(fd);
285
+ return ERR_VALIDATION;
286
+ }
287
+
288
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
289
+ LOG_ERROR("connect(%s:%d) failed: %s", host, port, strerror(errno));
290
+ close(fd);
291
+ return ERR_IO;
292
+ }
293
+
294
+ return fd;
295
+ }
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Output Parameters for Results
301
+
302
+ ```c
303
+ /* GOOD: Return error code, write result to output parameter */
304
+ int config_get_int(const config_t *cfg, const char *key, int *out_value) {
305
+ if (!cfg || !key || !out_value) {
306
+ return ERR_NULL_PARAM;
307
+ }
308
+
309
+ const config_entry_t *entry = config_find(cfg, key);
310
+ if (!entry) {
311
+ return ERR_NOT_FOUND;
312
+ }
313
+
314
+ char *endptr = NULL;
315
+ long val = strtol(entry->value, &endptr, 10);
316
+ if (*endptr != '\0') {
317
+ return ERR_VALIDATION;
318
+ }
319
+
320
+ *out_value = (int)val;
321
+ return ERR_OK;
322
+ }
323
+
324
+ /* Usage */
325
+ int port;
326
+ int rc = config_get_int(&cfg, "server.port", &port);
327
+ if (rc != ERR_OK) {
328
+ LOG_ERROR("failed to read port: %s", error_string(rc));
329
+ port = DEFAULT_PORT;
330
+ }
331
+ ```
332
+
333
+ ---
334
+
335
+ ## Anti-Patterns
336
+
337
+ | Anti-Pattern | Problem | Correct Approach |
338
+ |---|---|---|
339
+ | Ignoring return values | Errors propagate silently, crash later | Always check; use `RETURN_IF_ERROR` macro |
340
+ | Nested if for resource cleanup | Pyramid of doom, missed frees | `goto cleanup` pattern |
341
+ | Duplicated cleanup at each error | Maintenance nightmare, easy to miss | Single `cleanup` label with all frees |
342
+ | Using `errno` without checking call result | `errno` is only valid after a failed call | Check return value first, then errno |
343
+ | Not saving `errno` before logging | `fprintf`/`log` may overwrite errno | Save to local variable immediately |
344
+ | Returning magic numbers | Caller cannot interpret meaning | Use named enum constants |
345
+ | `assert()` for runtime errors | Disabled in release builds | `assert` for programmer bugs only; return codes for runtime errors |
346
+ | `exit()` deep in library code | Prevents caller from handling error | Return error codes; let `main()` decide |
347
+
348
+ ---
349
+
350
+ _Errors in C are values. Return them, check them, propagate them, and always clean up. The goto cleanup pattern is your best friend for resource safety._
@@ -0,0 +1,158 @@
1
+ # Feedback Configuration
2
+
3
+ Project-specific commands for automated feedback during C implementation.
4
+
5
+ ---
6
+
7
+ ## Build Commands
8
+
9
+ Commands to build the project during implementation.
10
+
11
+ ```yaml
12
+ # Primary build command (REQUIRED)
13
+ build: cmake --build build
14
+
15
+ # Configure (first time or after CMakeLists changes)
16
+ configure: cmake --preset default
17
+
18
+ # Configure debug
19
+ configure_debug: cmake --preset debug
20
+
21
+ # Clean build
22
+ clean_build: cmake --build build --clean-first
23
+
24
+ # Release build
25
+ build_release: cmake --preset release && cmake --build build-release
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Test Commands
31
+
32
+ Commands to run tests during implementation. The agent will use these to verify code changes.
33
+
34
+ ```yaml
35
+ # Primary test command (REQUIRED)
36
+ test: ctest --test-dir build --output-on-failure
37
+
38
+ # Run specific test suite
39
+ test_suite: ctest --test-dir build -R "{suite_name}" --output-on-failure
40
+
41
+ # Run with verbose output
42
+ test_verbose: ctest --test-dir build -V
43
+
44
+ # Run only unit tests
45
+ test_unit: ctest --test-dir build -L unit --output-on-failure
46
+
47
+ # Run only integration tests
48
+ test_integration: ctest --test-dir build -L integration --output-on-failure
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Linting Commands
54
+
55
+ Commands for code quality checks.
56
+
57
+ ```yaml
58
+ # Primary lint command (clang-tidy)
59
+ lint: run-clang-tidy -p build
60
+
61
+ # Lint single file
62
+ lint_file: clang-tidy -p build {file}
63
+
64
+ # Lint with auto-fix
65
+ lint_fix: run-clang-tidy -p build -fix
66
+
67
+ # Static analysis with cppcheck
68
+ static_analysis: cppcheck --project=build/compile_commands.json --std=c17 --enable=all --error-exitcode=1
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Format Commands
74
+
75
+ Commands for code formatting.
76
+
77
+ ```yaml
78
+ # Format check (CI)
79
+ format_check: clang-format --dry-run --Werror $(find src include -name '*.c' -o -name '*.h')
80
+
81
+ # Format fix
82
+ format: clang-format -i $(find src include -name '*.c' -o -name '*.h')
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Sanitizer Builds
88
+
89
+ Commands for sanitizer-instrumented builds.
90
+
91
+ ```yaml
92
+ # ASan + UBSan build and test
93
+ test_asan: cmake --preset asan && cmake --build build-asan && ctest --test-dir build-asan --output-on-failure
94
+
95
+ # TSan build and test
96
+ test_tsan: cmake --preset tsan && cmake --build build-tsan && ctest --test-dir build-tsan --output-on-failure
97
+
98
+ # MSan build and test (Clang only)
99
+ test_msan: cmake -B build-msan -DCMAKE_C_FLAGS="-fsanitize=memory -fno-omit-frame-pointer" && cmake --build build-msan && ctest --test-dir build-msan --output-on-failure
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Coverage Commands
105
+
106
+ Commands for code coverage reporting.
107
+
108
+ ```yaml
109
+ # Build with coverage
110
+ build_coverage: cmake --preset coverage && cmake --build build-coverage
111
+
112
+ # Run tests and generate report
113
+ coverage: cmake --build build-coverage && ctest --test-dir build-coverage --output-on-failure && lcov --capture --directory build-coverage --output-file coverage.info && lcov --remove coverage.info '/usr/*' '*/test/*' '*/vendor/*' --output-file coverage.info && genhtml coverage.info --output-directory coverage-report/
114
+
115
+ # Quick coverage summary
116
+ coverage_summary: cmake --build build-coverage && ctest --test-dir build-coverage && gcovr --root . --print-summary
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Valgrind Commands
122
+
123
+ Commands for memory checking with Valgrind.
124
+
125
+ ```yaml
126
+ # Full leak check on executable
127
+ valgrind: valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --error-exitcode=1 ./build/myapp
128
+
129
+ # Valgrind on test binary
130
+ valgrind_tests: valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./build/tests/test_user
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Packaging Commands
136
+
137
+ Commands for packaging with CPack.
138
+
139
+ ```yaml
140
+ # Generate package
141
+ package: cd build && cpack
142
+
143
+ # Generate specific package type
144
+ package_tar: cd build && cpack -G TGZ
145
+ package_deb: cd build && cpack -G DEB
146
+ package_rpm: cd build && cpack -G RPM
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Notes
152
+
153
+ - Uses CMake as the build system with Ninja backend
154
+ - Requires `compile_commands.json` for clang-tidy (set `CMAKE_EXPORT_COMPILE_COMMANDS=ON`)
155
+ - vcpkg or Conan for dependency management
156
+ - ASan and TSan cannot be combined; run as separate CI jobs
157
+ - Unity is the primary test framework, CTest is the test runner
158
+ - Valgrind and ASan serve similar purposes; use ASan in CI for speed, Valgrind for deep investigation