Skip to content

feat!: S11.10 SolidSyslog core onto PoolAllocator (handle API)#416

Merged
DavidCozens merged 4 commits into
mainfrom
refactor/s11-10-solidsyslog-pool
May 20, 2026
Merged

feat!: S11.10 SolidSyslog core onto PoolAllocator (handle API)#416
DavidCozens merged 4 commits into
mainfrom
refactor/s11-10-solidsyslog-pool

Conversation

@DavidCozens

@DavidCozens DavidCozens commented May 20, 2026

Copy link
Copy Markdown
Owner

Purpose

Closes #413. Retrofits the SolidSyslog core itself onto the canonical
3-TU split + SolidSyslogPoolAllocator with a handle-taking public API.
The penultimate E11 story — the class-by-class sweep closed in S11.09;
only S11.11 (MISRA D.002 suppression cleanup) remains in E11.

Change Description

Two architectural commits + a DEVLOG (squash-merge collapses to one on main):

  • refactor: collapse Nil collaborators onto public Null siblings
    strips the ~120-line in-TU NilBuffer / NilSender / NilStore
    vtables, points the file-static defaults at the public
    SolidSyslogNull{Buffer,Sender,Store}_Get() siblings, drops the
    loud-once NIL_BUFFER_USED / NIL_SENDER_USED reporters and their 5
    asserting tests. Net deletion: 273 lines. No public-API change. The
    authoritative bad-config signal stays the Create-time NULL_BUFFER /
    NULL_SENDER error fired by _InstallBuffer / _InstallSender.

  • feat!: migrate SolidSyslog core onto PoolAllocator with handle API
    the architectural change. New Core/Source/SolidSyslogPrivate.h lifts
    struct SolidSyslog + _Initialise / _Cleanup signatures + the
    two TU-shared NullClock / NullStringFunction declarations into a
    private header. New Core/Source/SolidSyslogStatic.c carries the
    pool, allocator, _Create / _Destroy / IndexFromHandle /
    CleanupAtIndex, and the NullInstance exhaustion-fallback (lazy-
    populated because the SolidSyslogNull*_Get() addresses are runtime
    constants, no file-scope designated initialiser works). SolidSyslog.c
    keeps the algorithm: every instance.X reference becomes self->X,
    and _Log / _Service / _FormatMessage / _DrainBufferIntoStore /
    _SendOneFromStore / _IsServiceEnabled take a self parameter.
    _Initialise absorbs the per-slot Install* helpers; _Cleanup
    resets the slot to safe defaults.

    All four BDD targets (Linux, Windows, FreeRtos, Common) and every test
    fixture (SolidSyslog, SolidSyslogLifecycle,
    SolidSyslogServiceEagerDrain, BddTargetServiceThread,
    ServiceDrainInterleave, the PosixMessageQueueBuffer service test)
    thread a struct SolidSyslog* through.
    BddTargetInteractive_Run and BddTargetServiceThread_Run both gain
    a leading struct SolidSyslog* handle parameter.

  • docs: update DEVLOG and CLAUDE.md — full decisions narrative,
    per-class delta numbers, validation matrix in DEVLOG; audience-table
    rows for SolidSyslog.h / SolidSyslogConfig.h updated for the
    handle API in CLAUDE.md.

Public API change

/* Before */
void                       SolidSyslog_Create(const SolidSyslogConfig*);
void                       SolidSyslog_Destroy(void);
void                       SolidSyslog_Log(const SolidSyslogMessage*);
void                       SolidSyslog_Service(void);

/* After */
struct SolidSyslog*        SolidSyslog_Create(const SolidSyslogConfig*);
void                       SolidSyslog_Destroy(struct SolidSyslog*);
void                       SolidSyslog_Log(struct SolidSyslog*, const SolidSyslogMessage*);
void                       SolidSyslog_Service(struct SolidSyslog*);

The five process-global library functions
(_SetErrorHandler, _Error, _SetConfigLock, _LockConfig,
_UnlockConfig) stay process-global — multi-instance does not change
library-wide error/lock semantics; the ConfigLock-protects-the-Pool
chicken-and-egg forces them global anyway.

New SOLIDSYSLOG_POOL_SIZE tunable, default 1U.

MSG_NIL_BUFFER_USED, MSG_NIL_SENDER_USED, MSG_CREATE_ALREADY_INITIALISED
deleted from SolidSyslogErrorMessages.h.
MSG_SOLIDSYSLOG_POOL_EXHAUSTED, MSG_SOLIDSYSLOG_UNKNOWN_DESTROY,
MSG_LOG_NULL_HANDLE, MSG_SERVICE_NULL_HANDLE added.

Decisions worth flagging

  • NullInstance, not NilInstance — agreed pre-coding. Once the
    collaborator slots route through public Null siblings, "Nil" is a
    historical name.
  • Class-specific MSG_SOLIDSYSLOG_POOL_EXHAUSTED — agreed
    pre-coding. Matches every other E11 class's
    MSG_<CLASS>_POOL_EXHAUSTED / _UNKNOWN_DESTROY shape.
  • Story commits 2 + 3 collapsed. The story body sequenced commit 2
    as "core + tests" and commit 3 as "consumer-side updates" with
    commit 2 "compiles but doesn't link end-to-end". CMake doesn't offer
    a granular compile-without-link knob; splitting them per the recipe
    would have left the debug build broken between commits. Collapsed
    into the single feat! commit so the per-commit must-compile
    invariant holds. The squash-merged PR collapses to one commit
    anyway, so on-main history is identical to the story body's plan.
  • NullInstance lazy-populated. Forced by C99: file-scope
    designated initialisers can't reference runtime constants like
    SolidSyslogNullBuffer_Get(). _Create always touches the
    fallback so the lazy populate runs on first reach.
  • Forged unknown handle for the bad-Destroy tests via
    reinterpret_cast<struct SolidSyslog*>(&stackByte)struct SolidSyslog is opaque in the public headers (private shape lives in
    SolidSyslogPrivate.h, internal-only), so a declared local won't
    compile. NOLINT'd at each site.

Test Evidence

New SolidSyslogPoolTest.cpp — 9 tests mirroring
SolidSyslogStdAtomicCounterPool's canonical shape (fill, overflow,
fallback semantics, ConfigLock probe semantics, unknown/stale handle
Destroy).

NULL-handle defensive coverage on _Log / _Service added to the
SolidSyslogLifecycle group (LogWithNullHandleReportsError,
ServiceWithNullHandleReportsError,
DestroyWithNullHandleReportsWarning,
DestroyWithUnknownHandleReportsWarning).

Five legacy tests deleted (the loud-once NIL reporter asserters, no
longer reachable). Two "second Create" tests rewritten as pool-
exhaustion tests inside the new Pool TEST_GROUP. Existing 100+
tests migrated mechanically to the handle API.

Local validation (gcc devcontainer)

  • debug: 1282 tests pass.
  • debug @ SOLIDSYSLOG_POOL_SIZE=3 via tunable-override-debug:
    1280 tests pass (the two pool-size-1-specific exhaustion tests now
    exercise three-slot fills via the Pool TEST_GROUP's FillPool).
  • sanitize: 1282 tests pass; pre-existing UBSan finding on
    Tests/FileFake.c:424 from S10.04 unchanged.
  • coverage: aggregated 99.9% line; 100% line on every
    new/migrated file
    SolidSyslog.c 225/225,
    SolidSyslogStatic.c 41/41.
  • analyze-tidy: clean.
  • analyze-cppcheck: clean (no new findings vs main).
  • analyze-format: clean.
  • IWYU: clean via the cpputest-clang container.
  • OpenSSL integration suite: green.

CI-only gates expected to pass

  • build-windows-msvc — Windows BDD target threads the handle.
  • bdd-windows-otel — exercises Windows main's lifecycle.
  • bdd-linux-syslog-ng — Linux main threads the handle.
  • bdd-freertos-qemu — FreeRtos main's lifecycle-mutex + handle
    pattern across RebuildWithFileStore and TeardownAll.

Areas Affected

  • Core/Interface/SolidSyslog.h + SolidSyslogConfig.h
    signature change (breaking).
  • Core/Interface/SolidSyslogTunablesDefaults.h — new
    SOLIDSYSLOG_POOL_SIZE (default 1U).
  • Core/Source/SolidSyslog.c — 568 → 567 lines, function bodies
    reach through self not instance.
  • Core/Source/SolidSyslogPrivate.h (new, 41 lines) — struct
    definition + private signatures.
  • Core/Source/SolidSyslogStatic.c (new, 99 lines) — Pool,
    Allocator, Create, Destroy, IndexFromHandle, CleanupAtIndex,
    NullInstance.
  • Core/Source/SolidSyslogErrorMessages.h — message-string churn
    (see Public API change section above).
  • Bdd/Targets/{Linux,Windows,FreeRtos}/ — store the handle as a
    file-static (Linux/Windows) or globally-visible static (FreeRtos)
    and thread it through Interactive_Run / ServiceThread_Run / Service.
  • Bdd/Targets/Common/BddTargetInteractive.{h,c}_Run gains
    struct SolidSyslog* handle leading parameter.
  • Bdd/Targets/Common/BddTargetServiceThread.{h,c}_Run gains
    struct SolidSyslog* handle leading parameter.
  • Tests/ — five fixtures grow a solidSyslog member, every
    _Create/_Destroy/_Log/_Service callsite gets the handle. New
    SolidSyslogPoolTest.cpp (178 lines, 9 tests).
  • Tests/Fixtures/SmallMessageSizeTunables.hSOLIDSYSLOG_POOL_SIZE
    bumped to 3U for the tunable-override-debug preset.
  • CLAUDE.md — audience-table rows for SolidSyslog.h /
    SolidSyslogConfig.h updated.
  • DEVLOG.md — S11.10 entry.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Support for multiple independent syslog instances via new handle-based API
    • Configurable pool size tunable for managing instance allocations in embedded environments
  • Breaking Changes

    • All core syslog operations (create, log, service, destroy) now require instance handle parameters
    • Applications must now manage returned syslog instance handles explicitly

Review Change Stack

Replace the three TU-local Nil vtables (NilBuffer/NilSender/NilStore) with
their public Null siblings. Drop the loud-once NIL_BUFFER_USED /
NIL_SENDER_USED reporters — the authoritative bad-config signal is the
Create-time NULL_BUFFER / NULL_SENDER error, not a runtime first-use report.

The NilInstance file-static template can no longer be a designated initialiser
because SolidSyslogNull*_Get() returns runtime addresses. Replaced with
SolidSyslog_ResetInstanceToDefaults() called from _Create and _Destroy, and a
SolidSyslog_EnsureInstanceInitialised() lazy-init guard at every entry point
to preserve pre-Create / post-Destroy crash safety. (Both helpers disappear in
the next commit when instance becomes a Pool[] slot.)

NilClock / NilStringFunction renamed to NullClock / NullStringFunction; no
public Null equivalent exists for the function-pointer typedefs, so they stay
TU-local.

Five tests deleted: LogBeforeCreateReportsNilBufferUsedOnce,
RepeatedLogBeforeCreateReportsNilBufferUsedOnlyOnce, DestroyReArmsNilBufferReporter,
ServiceWithNilSenderReportsNilSenderUsed, RepeatedServiceWithNilSenderReportsNilSenderUsedOnlyOnce,
DestroyReArmsNilSenderReporter. ServiceWithNilStoreDrainsThroughToRealSender
renamed to ServiceWithDefaultStoreDrainsThroughToRealSender — same behaviour
(NullStore.IsTransient = true), updated name reflects the collapsed defaults.

SolidSyslog.c shrinks by ~140 lines. No public API change.
… API

Retrofits the SolidSyslog core onto the canonical 3-TU split
(SolidSyslog.c + SolidSyslogPrivate.h + SolidSyslogStatic.c) backed by
SolidSyslogPoolAllocator. Public API now takes a handle:

  struct SolidSyslog* SolidSyslog_Create(const SolidSyslogConfig*);
  void                SolidSyslog_Destroy(struct SolidSyslog*);
  void                SolidSyslog_Log(struct SolidSyslog*, const SolidSyslogMessage*);
  void                SolidSyslog_Service(struct SolidSyslog*);

The five process-global library functions (SetErrorHandler, Error,
SetConfigLock, LockConfig, UnlockConfig) stay process-global — multi-instance
does not change library-wide error/lock semantics.

SOLIDSYSLOG_POOL_SIZE tunable (default 1U) added to TunablesDefaults.h. Pool
exhaustion returns &NullInstance (TU-private template wired to public
SolidSyslogNull{Buffer,Sender,Store}_Get() siblings; collaborator slots
populated lazily because the Null*_Get() addresses are runtime constants) and
fires SOLIDSYSLOG_POOL_EXHAUSTED. _Log/_Service against the fallback dispatch
through Null vtables and silently drop. _Destroy(unknown) and _Destroy(NULL)
fire WARNING + ignore via the existing IndexFromHandle pattern.

Defensive paths added: LOG_NULL_HANDLE and SERVICE_NULL_HANDLE on NULL handle
to the runtime entry points. The CREATE_ALREADY_INITIALISED error message
goes away — multi-Create now allocates distinct pool slots or fires
POOL_EXHAUSTED, the legacy double-Create-into-singleton semantic is gone.

New SolidSyslogPoolTest.cpp — 9 tests mirroring SolidSyslogWindowsMutexPool's
canonical shape (fill, overflow, fallback, lock semantics, unknown-handle).
SolidSyslog and SolidSyslogLifecycle TEST_GROUPs migrated to the handle API.
The two legacy "second Create" tests were replaced by the equivalent pool
tests; the loud-once Nil reporter assertions were already dropped in the
preceding commit.

BDD targets (Linux/Windows/FreeRtos/Common) updated to store the handle and
thread it through BddTargetInteractive_Run and BddTargetServiceThread_Run,
both of which gain a struct SolidSyslog* handle parameter.

Tests/Fixtures/SmallMessageSizeTunables.h bumps SOLIDSYSLOG_POOL_SIZE to 3
so the tunable-override-debug preset exercises multi-instance pool walks.

Validation (gcc devcontainer): debug, sanitize, coverage, analyze-tidy,
analyze-cppcheck, analyze-format all green; 1282 tests pass at the default
pool size 1 AND at the bumped pool size 3 (tunable-override-debug). IWYU
clean via cpputest-clang. SolidSyslog.c and SolidSyslogStatic.c at 100% line
coverage.
DEVLOG entry covers the two-commit shape, decisions (NullInstance rename,
class-specific POOL_EXHAUSTED message, lazy population), per-class delta
numbers, and the local validation matrix. CLAUDE.md audience-table rows
for SolidSyslog.h and SolidSyslogConfig.h updated for the handle-taking
API and the new SOLIDSYSLOG_POOL_SIZE tunable.

Closes #413.
@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@DavidCozens has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 50 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b72b242-808e-4535-85d5-b32de1d64232

📥 Commits

Reviewing files that changed from the base of the PR and between 51cf72b and cc101aa.

📒 Files selected for processing (1)
  • Core/Source/SolidSyslogStatic.c
📝 Walkthrough

Walkthrough

The pull request refactors SolidSyslog from a global singleton to a handle-based, pool-backed design. Public API functions now accept and return struct SolidSyslog* handles; a new pool allocator manages multiple instances with null-instance fallback on exhaustion. Core algorithm updated to work per-instance. All platforms and tests adapted to the new API.

Changes

Handle-based pool-backed SolidSyslog core

Layer / File(s) Summary
Public API contracts and forward declarations
Core/Interface/SolidSyslog.h, Core/Interface/SolidSyslogConfig.h, Bdd/Targets/Common/BddTargetInteractive.h, Bdd/Targets/Common/BddTargetServiceThread.h
struct SolidSyslog is forward-declared as opaque; SolidSyslog_Create returns struct SolidSyslog*, SolidSyslog_Destroy takes a handle, and SolidSyslog_Log/SolidSyslog_Service now require handles as first parameter. BDD harness functions updated to accept and pass handles.
Pool allocator and lifecycle management
Core/Source/SolidSyslogStatic.c, Core/Source/SolidSyslogPrivate.h
New pool allocator with SolidSyslog_Create that acquires free pool slots or returns TU-private NilInstance on exhaustion; SolidSyslog_Destroy releases slots by handle lookup; SolidSyslog_IndexFromHandle performs linear search; NilInstance provides null-vtable fallback with no-op clock and string functions.
Core algorithm and handle-based message flow
Core/Source/SolidSyslog.c
Refactored to SolidSyslog_Initialise/Cleanup per-instance; SolidSyslog_Service(handle) drains buffer into store and sends via per-handle drain/send helpers; SolidSyslog_Log(handle, message) formats and buffers using instance fields; SolidSyslog_FormatMessage now takes handle to pull hostname/appname/process-id from instance.
Tunable pool size and error messages
Core/Interface/SolidSyslogTunablesDefaults.h, Core/Source/SolidSyslogErrorMessages.h
SOLIDSYSLOG_POOL_SIZE tunable (default 1U) with compile-time >= 1 check; new error macros for NULL log/service handles, pool exhaustion, and unknown destroy; removed old macros for already-initialised and nil-buffer/sender-used conditions.
Build configuration
Core/Source/CMakeLists.txt
SolidSyslogStatic.c added to library sources.
BDD platform integration
Bdd/Targets/FreeRtos/main.c, Bdd/Targets/Linux/main.c, Bdd/Targets/Windows/BddTargetWindows.c, Bdd/Targets/Common/BddTargetInteractive.c, Bdd/Targets/Common/BddTargetServiceThread.c
All platforms create SolidSyslog at startup, store instances as file-scope pointers, pass handles to interactive and service thread runners, and destroy instances at shutdown; BddTargetInteractive_Run and BddTargetServiceThread_Run accept and use handle parameters.
Test suite and pool allocator coverage
Tests/SolidSyslogPoolTest.cpp, Tests/SolidSyslogTest.cpp, Tests/SolidSyslogBlockStoreDrainOrderingTest.cpp, Tests/SolidSyslogPosixMessageQueueBufferTest.cpp, Tests/Bdd/Targets/BddTargetInteractiveTest.cpp, Tests/Bdd/Targets/BddTargetServiceThreadTest.cpp, Tests/CMakeLists.txt, Tests/Fixtures/SmallMessageSizeTunables.h
New SolidSyslogPoolTest.cpp with 9 tests covering pool overflow, exhaustion, fallback properties, lock behavior, and error reporting; all existing test fixtures and cases refactored to create instances, pass handles to Log/Service, and manage instance lifecycle; SmallMessageSizeTunables.h defines SOLIDSYSLOG_POOL_SIZE 3U for test pool exercises.
Documentation
CLAUDE.md, DEVLOG.md
CLAUDE.md updated to document handle-based signatures and opaque struct; DEVLOG.md S11.10 entry records design decisions, per-class migration, test updates, validation results, and CI handoff status.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

  • DavidCozens/solid-syslog#413: This PR directly implements the S11.10 retrofit objective to convert SolidSyslog from singleton to handle-based pool-backed design with PoolAllocator, new private struct, Create/Destroy returning/accepting handles, and NULL-handle/exhaustion fallback behavior.

Possibly related PRs

  • DavidCozens/solid-syslog#396: Directly connected; this PR's pool-slot management and allocator logic is extracted into the pool-backed lifecycle that the main PR integrates.
  • DavidCozens/solid-syslog#327: Overlaps in defensive nil-object defaults for pre-init/post-destroy/NULL input scenarios that the main PR handles via pool exhaustion fallback and NULL-handle validation.
  • DavidCozens/solid-syslog#84: Both PRs directly refactor SolidSyslog_Service implementation and the service pipeline (drain/send) that the main PR makes per-instance via handles.

Poem

🐰 A Rabbit's Ode to Pooled Instances

Once global, now pooled with handles so fair,
The syslog instances dance everywhere,
Null-instance fallback when slots run dry,
Each platform adapts—the refactor runs high! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat!: S11.10 SolidSyslog core onto PoolAllocator (handle API)' is specific, concise, and accurately describes the main breaking change: migrating SolidSyslog to a pool-backed handle-based API.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering Purpose, Change Description, Test Evidence, and Areas Affected with detailed explanations of architectural decisions and validation results.
Linked Issues check ✅ Passed The PR implementation fully addresses issue #413 requirements: 3-TU split with pool-backed design, handle-based public API (Create returns handle, Destroy/Log/Service take handle), SOLIDSYSLOG_POOL_SIZE tunable, NilInstance exhaustion fallback, collapsed Nil collaborators, NULL-handle defensive checks, error-message updates, new SolidSyslogPoolTest.cpp, updated BDD targets/tests, and validation across all platforms.
Out of Scope Changes check ✅ Passed All changes align with issue #413 scope: core refactoring (SolidSyslog.c, new Private/Static headers), public API migration (SolidSyslog.h, SolidSyslogConfig.h), pool tunable (TunablesDefaults.h), error messages, BDD targets, tests, and documentation (DEVLOG, CLAUDE.md). No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/s11-10-solidsyslog-pool

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
Core/Source/SolidSyslog.c (1)

246-247: ⚡ Quick win

Extract inlined composite if conditions into intent-named helpers.

These two conditions are now inlined in if statements. Please move the composite predicate logic behind static inline bool IsXxx(...) helpers for consistency with project rules.

Proposed refactor
+static inline bool SolidSyslog_ShouldBypassTransientStore(
+    struct SolidSyslog* self,
+    const char* buf,
+    size_t len
+);
+static inline bool SolidSyslog_TryReadAndSendOne(
+    struct SolidSyslog* self,
+    char* buf,
+    size_t bufSize,
+    size_t* len
+);
...
-        if (!SolidSyslogStore_Write(self->Store, buf, len) && SolidSyslogStore_IsTransient(self->Store))
+        if (SolidSyslog_ShouldBypassTransientStore(self, buf, len))
         {
             SolidSyslogSender_Send(self->Sender, buf, len);
         }
...
-    if (SolidSyslogStore_ReadNextUnsent(self->Store, buf, sizeof(buf), &len) &&
-        SolidSyslogSender_Send(self->Sender, buf, len))
+    if (SolidSyslog_TryReadAndSendOne(self, buf, sizeof(buf), &len))
     {
         SolidSyslogStore_MarkSent(self->Store);
     }

As per coding guidelines: Core/Source/**/*.c: When a composite condition is inlined into an if or return, extract a static inline bool IsXxx(...) helper with intent-naming.

Also applies to: 258-259

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Source/SolidSyslog.c` around lines 246 - 247, Extract the composite
predicate "!SolidSyslogStore_Write(self->Store, buf, len) &&
SolidSyslogStore_IsTransient(self->Store)" (and the similar expression at the
other occurrence) into a static inline bool helper with an intent name (e.g.
static inline bool IsTransientStoreWriteFailure(SolidSyslog *self, const void
*buf, size_t len) or a name matching the function intent), implement the helper
to call SolidSyslogStore_Write and SolidSyslogStore_IsTransient appropriately,
and replace the inlined conditions in the if statements with calls to that
helper; ensure the helper is declared static inline in Core/Source/SolidSyslog.c
above the functions that use it and that parameter types match the calling
context (use self->Store, buf, len).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLAUDE.md`:
- Line 314: The docs contain a typo: the tunable macro is referenced as
SOLIDSYSYSLOG_POOL_SIZE but the correct macro is SOLIDSYSLOG_POOL_SIZE; update
the public-header inventory row text so it references SOLIDSYSLOG_POOL_SIZE (and
preserve the naming convention SOLIDSYSLOG_SCREAMING_SNAKE), ensuring the
surrounding descriptive text for SolidSyslogConfig.h / SolidSyslog_Create /
SolidSyslog_Destroy still accurately describes the pool, NullInstance fallback,
and related Null vtable functions.

In `@DEVLOG.md`:
- Line 155: Update the DEVLOG entry to fix the header filename typo: replace the
incorrect `SolidSyslogPrival.h` reference with the correct
`SolidSyslogPrivate.h` and mention `SolidSyslogStatic.c` as the file that
included it so readers tracing the include issue are directed to the right
header name and source file.

---

Nitpick comments:
In `@Core/Source/SolidSyslog.c`:
- Around line 246-247: Extract the composite predicate
"!SolidSyslogStore_Write(self->Store, buf, len) &&
SolidSyslogStore_IsTransient(self->Store)" (and the similar expression at the
other occurrence) into a static inline bool helper with an intent name (e.g.
static inline bool IsTransientStoreWriteFailure(SolidSyslog *self, const void
*buf, size_t len) or a name matching the function intent), implement the helper
to call SolidSyslogStore_Write and SolidSyslogStore_IsTransient appropriately,
and replace the inlined conditions in the if statements with calls to that
helper; ensure the helper is declared static inline in Core/Source/SolidSyslog.c
above the functions that use it and that parameter types match the calling
context (use self->Store, buf, len).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8f1fe227-6c6f-4152-b70b-07aca16320b3

📥 Commits

Reviewing files that changed from the base of the PR and between e4531e2 and 51cf72b.

📒 Files selected for processing (25)
  • Bdd/Targets/Common/BddTargetInteractive.c
  • Bdd/Targets/Common/BddTargetInteractive.h
  • Bdd/Targets/Common/BddTargetServiceThread.c
  • Bdd/Targets/Common/BddTargetServiceThread.h
  • Bdd/Targets/FreeRtos/main.c
  • Bdd/Targets/Linux/main.c
  • Bdd/Targets/Windows/BddTargetWindows.c
  • CLAUDE.md
  • Core/Interface/SolidSyslog.h
  • Core/Interface/SolidSyslogConfig.h
  • Core/Interface/SolidSyslogTunablesDefaults.h
  • Core/Source/CMakeLists.txt
  • Core/Source/SolidSyslog.c
  • Core/Source/SolidSyslogErrorMessages.h
  • Core/Source/SolidSyslogPrivate.h
  • Core/Source/SolidSyslogStatic.c
  • DEVLOG.md
  • Tests/Bdd/Targets/BddTargetInteractiveTest.cpp
  • Tests/Bdd/Targets/BddTargetServiceThreadTest.cpp
  • Tests/CMakeLists.txt
  • Tests/Fixtures/SmallMessageSizeTunables.h
  • Tests/SolidSyslogBlockStoreDrainOrderingTest.cpp
  • Tests/SolidSyslogPoolTest.cpp
  • Tests/SolidSyslogPosixMessageQueueBufferTest.cpp
  • Tests/SolidSyslogTest.cpp

Comment thread CLAUDE.md
| `SolidSyslog.h` | Application code that logs events | `SolidSyslogMessage`, `SolidSyslog_Log`, `SolidSyslog_Service` |
| `SolidSyslogConfig.h` | System setup code | `SolidSyslogConfig`, `SolidSyslog_Create`, `SolidSyslog_Destroy` |
| `SolidSyslog.h` | Application code that logs events | `SolidSyslogMessage`, `SolidSyslog_Log(handle, message)`, `SolidSyslog_Service(handle)`. `struct SolidSyslog` opaque. |
| `SolidSyslogConfig.h` | System setup code | `SolidSyslogConfig`, `SolidSyslog_Create(config) → handle`, `SolidSyslog_Destroy(handle)`. Instance struct lives in a library-internal static pool (E11; tunable `SOLIDSYSLOG_POOL_SIZE`, default `1U`). Pool-exhaustion fallback is a TU-private `NullInstance` wired to `SolidSyslogNull{Buffer,Sender,Store}_Get()` siblings — `_Log`/`_Service` against it dispatch through Null vtables and silently drop. |

@coderabbitai coderabbitai Bot May 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix macro typo in public-header inventory row.

Line 314 documents SOLIDSYSYSLOG_POOL_SIZE, but the tunable name is SOLIDSYSLOG_POOL_SIZE.

📝 Proposed docs fix
-| `SolidSyslogConfig.h` | System setup code | `SolidSyslogConfig`, `SolidSyslog_Create(config) → handle`, `SolidSyslog_Destroy(handle)`. Instance struct lives in a library-internal static pool (E11; tunable `SOLIDSYSYSLOG_POOL_SIZE`, default `1U`). Pool-exhaustion fallback is a TU-private `NullInstance` wired to `SolidSyslogNull{Buffer,Sender,Store}_Get()` siblings — `_Log`/`_Service` against it dispatch through Null vtables and silently drop. |
+| `SolidSyslogConfig.h` | System setup code | `SolidSyslogConfig`, `SolidSyslog_Create(config) → handle`, `SolidSyslog_Destroy(handle)`. Instance struct lives in a library-internal static pool (E11; tunable `SOLIDSYSLOG_POOL_SIZE`, default `1U`). Pool-exhaustion fallback is a TU-private `NullInstance` wired to `SolidSyslogNull{Buffer,Sender,Store}_Get()` siblings — `_Log`/`_Service` against it dispatch through Null vtables and silently drop. |

As per coding guidelines: public macros follow SOLIDSYSLOG_SCREAMING_SNAKE.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| `SolidSyslogConfig.h` | System setup code | `SolidSyslogConfig`, `SolidSyslog_Create(config) → handle`, `SolidSyslog_Destroy(handle)`. Instance struct lives in a library-internal static pool (E11; tunable `SOLIDSYSLOG_POOL_SIZE`, default `1U`). Pool-exhaustion fallback is a TU-private `NullInstance` wired to `SolidSyslogNull{Buffer,Sender,Store}_Get()` siblings — `_Log`/`_Service` against it dispatch through Null vtables and silently drop. |
| `SolidSyslogConfig.h` | System setup code | `SolidSyslogConfig`, `SolidSyslog_Create(config) → handle`, `SolidSyslog_Destroy(handle)`. Instance struct lives in a library-internal static pool (E11; tunable `SOLIDSYSLOG_POOL_SIZE`, default `1U`). Pool-exhaustion fallback is a TU-private `NullInstance` wired to `SolidSyslogNull{Buffer,Sender,Store}_Get()` siblings — `_Log`/`_Service` against it dispatch through Null vtables and silently drop. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLAUDE.md` at line 314, The docs contain a typo: the tunable macro is
referenced as SOLIDSYSYSLOG_POOL_SIZE but the correct macro is
SOLIDSYSLOG_POOL_SIZE; update the public-header inventory row text so it
references SOLIDSYSLOG_POOL_SIZE (and preserve the naming convention
SOLIDSYSLOG_SCREAMING_SNAKE), ensuring the surrounding descriptive text for
SolidSyslogConfig.h / SolidSyslog_Create / SolidSyslog_Destroy still accurately
describes the pool, NullInstance fallback, and related Null vtable functions.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive — the file actually has SOLIDSYSLOG_POOL_SIZE (correct). The phantom SOLIDSYSYSLOG (extra SYS) appears in CodeRabbit's diff display but is not in the source. Verified by grep -n SOLIDSYSYSLOG CLAUDE.md (no match).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DavidCozens, you're correct — I apologise for the noise. Looking at both the diff and the file content, the text reads SOLIDSYSLOG_POOL_SIZE (correct). The erroneous SOLIDSYSYSLOG I cited does not exist in the source, as your grep confirms. This was a false positive on my part; no change is needed.

🐇 (ears down, appropriately sheepish)

Comment thread DEVLOG.md
SolidSyslog* handle` in others — the project's `.clang-format`
accepts both, both forms appear in formatted output.
- IWYU clean via cpputest-clang (caught one missing
`SolidSyslogPrival.h` include in `SolidSyslogStatic.c` and missing

@coderabbitai coderabbitai Bot May 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix header filename typo in validation note.

SolidSyslogPrival.h looks like a typo and should likely be SolidSyslogPrivate.h. This can mislead anyone tracing the include issue from the DEVLOG entry.

✏️ Suggested edit
-- `SolidSyslogPrival.h` include in `SolidSyslogStatic.c` and missing
+- `SolidSyslogPrivate.h` include in `SolidSyslogStatic.c` and missing
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`SolidSyslogPrival.h` include in `SolidSyslogStatic.c` and missing
`SolidSyslogPrivate.h` include in `SolidSyslogStatic.c` and missing
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DEVLOG.md` at line 155, Update the DEVLOG entry to fix the header filename
typo: replace the incorrect `SolidSyslogPrival.h` reference with the correct
`SolidSyslogPrivate.h` and mention `SolidSyslogStatic.c` as the file that
included it so readers tracing the include issue are directed to the right
header name and source file.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive — SolidSyslogPrival.h and SolidSyslogPrivate.h are two distinct files. Core/Interface/SolidSyslogPrival.h is the public header holding the facility/severity enums (SOLIDSYSLOG_SEVERITY_ERROR et al.); Core/Source/SolidSyslogPrivate.h is the TU-internal header holding struct SolidSyslog. SolidSyslogStatic.c includes both. The IWYU catch logged in the DEVLOG was specifically about the missing Prival include (for the severity enum used in SolidSyslog_Error(...) call sites).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DavidCozens Got it — thanks for the clarification. I withdraw the suggestion; the DEVLOG entry is correct as written with the missing Prival include noted in SolidSyslogStatic.c. No change needed.


✏️ Learnings added
Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 416
File: DEVLOG.md:155-155
Timestamp: 2026-05-20T17:56:08.543Z
Learning: There are two distinct headers: Core/Interface/SolidSyslogPrival.h (public facility/severity enums) and Core/Source/SolidSyslogPrivate.h (TU-internal struct SolidSyslog). SolidSyslogStatic.c includes both; the DEVLOG IWYU note referred specifically to adding the Prival include for the enum used at SolidSyslog_Error call sites.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1286 passed, 🙈 2 skipped)
   🚦   build-freertos-host-tdd: 100% successful (✔️ 1449 passed, 🙈 2 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 1238 passed, 🙈 2 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1238 passed, 🙈 2 skipped)
   🚦   integration-linux-openssl: 100% successful (✔️ 9 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 9 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 46 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 90% successful (✔️ 44 passed, 🙈 5 skipped)
   🚦   bdd-freertos-qemu: 73% successful (✔️ 36 passed, 🙈 13 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1127 passed, 🙈 1 skipped)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1238 passed, 🙈 2 skipped)
   ⚠️   Clang-Tidy: 1 warning (normal: 1)
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

The multi-line _Destroy call I wrote split arguments across lines in a
shape clang-format doesn't pick — it reflows back to two lines: the
&&-bridged AcquireFirstFree() and FreeIfInUse() calls each on a single
line. No semantic change. Caught by CI's analyze-format gate; local
git-diff-based format check missed it because the file's diff against
itself was empty by the time I ran the spot check.
@DavidCozens

Copy link
Copy Markdown
Owner Author

@coderabbitai re the nitpick on Core/Source/SolidSyslog.c lines 246-247 / 258-259 (extract composite if conditions into intent-named static inline bool IsXxx helpers): leaving as-is. The composite predicates are built from already-intent-named functions (SolidSyslogStore_Write, SolidSyslogStore_IsTransient, SolidSyslogStore_ReadNextUnsent, SolidSyslogSender_Send) — the &&-bridged shape reads as English and an extracted predicate would rename without clarifying. The CLAUDE.md design-pattern rule applies when a composite predicate would benefit from a name beyond what the underlying calls already say; not the case here. Also: this code is pre-existing in S11.10 — the refactor only re-pointed instance.Xself->X — so changing the shape would be outside this PR's scope.

Also re the docstring-coverage warning (16.36% vs the 80% default threshold): not addressing. The project's house style is to default to no comments (CLAUDE.md "Doing tasks" section: "Default to writing no comments. Only add one when the WHY is non-obvious"). 80% docstring coverage would directly contradict the project's own guidance.

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@DavidCozens: Both points noted and understood — I'll stand down on them.

  1. Composite predicates: The argument is sound — SolidSyslogStore_Write(...) && SolidSyslogStore_IsTransient(...) is already as readable as any extracted IsXxx name would be, and the change would be purely cosmetic. The pre-existing-code scope constraint is a good additional reason to leave it alone.

  2. Docstring coverage: The CLAUDE.md "no comments by default" rule is a deliberate project stance, and the 80% threshold would directly contradict it. I'll treat that warning as noise for this codebase going forward.

🐇


✏️ Learnings added
Learnt from: DavidCozens
URL: https://github.com/DavidCozens/solid-syslog/pull/416

Timestamp: 2026-05-20T17:56:17.007Z
Learning: In the solid-syslog project (C codebase), composite `if` predicates bridged with `&&` are intentionally left inline when all constituent functions already have intent-revealing names (e.g. `SolidSyslogStore_Write`, `SolidSyslogStore_IsTransient`). Do not suggest extracting them into `static inline bool IsXxx` helpers — extracting would rename without clarifying. See `Core/Source/SolidSyslog.c`.

Learnt from: DavidCozens
URL: https://github.com/DavidCozens/solid-syslog/pull/416

Timestamp: 2026-05-20T17:56:17.007Z
Learning: The solid-syslog project's house style (documented in CLAUDE.md "Doing tasks" section) is to default to writing NO comments in source code. A comment is only added when the WHY is non-obvious. Do not flag low docstring/comment coverage — the 80% threshold (or any similar threshold) directly contradicts the project's own guidance. Never raise docstring-coverage warnings for this codebase.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1286 passed, 🙈 2 skipped)
   🚦   build-freertos-host-tdd: 100% successful (✔️ 1449 passed, 🙈 2 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 1238 passed, 🙈 2 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1238 passed, 🙈 2 skipped)
   🚦   integration-linux-openssl: 100% successful (✔️ 9 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 9 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 46 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 90% successful (✔️ 44 passed, 🙈 5 skipped)
   🚦   bdd-freertos-qemu: 73% successful (✔️ 36 passed, 🙈 13 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1127 passed, 🙈 1 skipped)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1238 passed, 🙈 2 skipped)
   ⚠️   Clang-Tidy: 1 warning (normal: 1)
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@DavidCozens DavidCozens merged commit 49a2e3c into main May 20, 2026
20 checks passed
@DavidCozens DavidCozens deleted the refactor/s11-10-solidsyslog-pool branch May 20, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

S11.10: Retrofit SolidSyslog core onto PoolAllocator (handle-taking API)

1 participant