Skip to content

feat(filestore): configurable capacity threshold alert (S05.09)#240

Merged
DavidCozens merged 12 commits into
mainfrom
feat/capacity-threshold-alert
May 2, 2026
Merged

feat(filestore): configurable capacity threshold alert (S05.09)#240
DavidCozens merged 12 commits into
mainfrom
feat/capacity-threshold-alert

Conversation

@DavidCozens

@DavidCozens DavidCozens commented May 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds SolidSyslogStoreThresholdFunction / SolidSyslogStoreThresholdCallback typedefs and three paired config fields (getCapacityThreshold, onThresholdCrossed, thresholdContext) to SolidSyslogFileStoreConfig.
  • Edge-triggered firing in BlockSequence: rises once when UsedBytes >= threshold, latches via a thresholdCrossed bool, clears on falling edge so DISCARD_OLDEST scenarios re-arm naturally.
  • Disabled by NULL function, NULL callback, or zero-return — all three exit cleanly.
  • Order at 100% with HALT defined: PrepareForWrite's file-full + store-full branch sets the sticky 100% bit, runs the threshold check, then dispatches onStoreFull so the warning fires before the terminal callback.
  • Fires once on Create when persisted usage is already at-or-above threshold (BlockSequence_Open runs the check after recovering write position).
  • Threaded example wires the callback to a marker file so BDD can assert invocation; new Bdd/Features/capacity_threshold.feature covers happy-path fire and below-threshold no-fire.
  • Docs: Core/Interface/SolidSyslogFileStore.h typedef comments include the NullBuffer recursion gotcha; CLAUDE.md "Public header audiences" row updated; docs/iec62443.md CR 2.9 / CR 2.10 rows replace the gap-flag wording.

Test plan

  • cmake --build --preset debug + ./build/debug/Tests/SolidSyslogTests (967 tests, 100% pass)
  • cmake --build --preset clang-debug (gcc + clang both green)
  • cmake --build --preset sanitize ASan/UBSan
  • cmake --build --preset coverage — 100% line + function (1667/1667 lines, 367/367 functions)
  • cmake --build --preset tidy — clang-tidy clean
  • cmake --build --preset cppcheck — clean
  • clang-format --dry-run --Werror on all touched files
  • behave Bdd/Features/capacity_threshold.feature (2 scenarios, both pass)
  • CI: build-windows-msvc, integration-linux-openssl, bdd-linux-syslog-ng, bdd-windows-otel, summary

Sliced 11 ways with strict TDD per feedback_slice_by_slice_review — every production change driven by a failing test, refactor under green following SOLID/DRY. DEVLOG entry recorded.

Closes #111

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added capacity threshold alert functionality with configurable byte-level thresholds and edge-triggered callbacks that fire when file-store usage crosses the configured threshold.
    • Added --capacity-threshold command-line option to configure the alert threshold.
  • Documentation

    • Updated public API documentation and compliance matrix to reflect capacity threshold alert behavior.

DavidCozens added 12 commits May 2, 2026 19:21
…uence

Slice 1 of S05.09. Adds SolidSyslogStoreThresholdFunction and
SolidSyslogStoreThresholdCallback typedefs plus the three new
SolidSyslogFileStoreConfig fields (getCapacityThreshold,
onThresholdCrossed, thresholdContext), and threads them through
BlockSequenceConfig/BlockSequence. Minimal firing path: any
record-write invokes onThresholdCrossed when non-NULL — edge
detection and threshold comparison land in subsequent slices.
Slice 2 of S05.09. Adds thresholdCrossed bool to BlockSequence and
gates NotifyThresholdCrossed on it being false, so consecutive writes
that keep usage above threshold do not refire the callback. The bit
is set on first fire and (for now) never cleared — re-arm after a
drop lands in slice 3.
…reshold

Slice 3 of S05.09. NotifyThresholdCrossed now reads the threshold and
compares against BlockSequence_UsedBytes. On a falling edge (used <
threshold) it clears thresholdCrossed so the callback re-arms; on a
rising edge it fires once and latches the bit. Verifies re-arm under
DISCARD_OLDEST when the threshold sits inside the active block.
…abled

Slice 4 of S05.09. Adds ThresholdEnabled helper that gates the firing
path on both callbacks being non-NULL, and treats threshold == 0 as
disabled (clears any latched edge state). Spec calls these out as
distinct ways to disable the feature without nulling onThresholdCrossed.
…backs

Slice 5 of S05.09. Pure regression guard — the plumbing already wires
thresholdContext through (added in slice 1), but the test pins down
that contract: both getCapacityThreshold and onThresholdCrossed receive
the configured context, mirroring storeFullContext's role.
…ty exhaustion

Slice 6 of S05.09. When PrepareForWrite hits the file-full + store-full
branch, engage the sticky 100% bit, then run the threshold check so it
sees usage = total, then fall through to NotifyStoreFull. Spec defines
this ordering at the 100% case so the 'approaching capacity' alert fires
before the terminal 'at capacity' callback. Sticky-bit assignment moves
out of NotifyStoreFull into the call site to make the sequencing explicit.
Slice 7 of S05.09. Pure regression guard. Once a failed Write has
latched thresholdCrossed and engaged the sticky bit, subsequent failed
Writes find the bit still set and skip firing — exactly the spec's
'sticky 100% does not re-fire' requirement. Comes free from slice 2's
edge-state latch and slice 6's sticky-first ordering.
…ge is above

Slice 8 of S05.09. After ScanForExistingFiles + write-position recovery,
BlockSequence_Open now runs NotifyThresholdCrossed so the callback fires
once on Create when the integrator restarts above an existing threshold.
…ext Write

Slice 9 of S05.09. Pure regression guard. Because NotifyThresholdCrossed
fetches the threshold via getCapacityThreshold on every Write, a runtime
change to a value below current usage naturally fires on the next Write
without needing a setter or notification path.
Slice 10 of S05.09. CLAUDE.md "Public header audiences" row for
SolidSyslogFileStore.h now lists the threshold typedefs and config
fields (with NullBuffer recursion pointer to the header). iec62443.md
CR 2.9 / CR 2.10 rows replace the gap-flag wording with the implemented
behaviour, including the at-100% ordering with HALT.

The header doc-comment for the typedefs (with the NullBuffer recursion
gotcha) landed in slice 1.
Slice 11 of S05.09. Threaded example now wires getCapacityThreshold +
onThresholdCrossed when --capacity-threshold N is supplied; the callback
appends a line to /tmp/solidsyslog_threshold_marker.log so BDD steps can
detect invocation. Two scenarios cover the rising-edge fire and the
no-fire-while-below-threshold case; environment.py cleans the marker
between scenarios.
@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR implements a configurable capacity threshold alert mechanism for the SolidSyslog file store. It adds edge-triggered threshold callbacks (SolidSyslogStoreThresholdFunction and SolidSyslogStoreThresholdCallback) to SolidSyslogFileStoreConfig, wires threshold-crossing detection into BlockSequence's write path, extends the example CLI and threaded application with threshold support, and validates the feature through comprehensive unit tests and BDD scenarios.

Changes

Capacity Threshold Alert Feature

Layer / File(s) Summary
Type Definitions & Config Structure
Core/Interface/SolidSyslogFileStore.h, Core/Source/BlockSequence.h, Example/Common/ExampleCommandLine.h
New callback typedefs SolidSyslogStoreThresholdFunction and SolidSyslogStoreThresholdCallback added. SolidSyslogFileStoreConfig extends with getCapacityThreshold, onThresholdCrossed, and thresholdContext. BlockSequenceConfig and BlockSequence structs add corresponding threshold fields and internal state tracking (thresholdCrossed, atCapacity). ExampleOptions adds capacityThreshold field.
Core Threshold Logic
Core/Source/BlockSequence.c
New ThresholdEnabled and NotifyThresholdCrossed helpers implement edge-triggered threshold crossing. On Open, fires callback if resumed usage exceeds threshold. During PrepareForWrite, threshold is checked before store-full callback, ensuring correct firing order. After each record write, threshold crossing is re-evaluated.
Integration & Wiring
Core/Source/SolidSyslogFileStore.c, Example/Common/ExampleCommandLine.c, Example/Threaded/main.c
BuildBlockSequenceConfig forwards threshold config fields from FileStore to BlockSequence. CLI parser adds --capacity-threshold option with positive-number validation. Threaded example implements GetCapacityThreshold callback and OnThresholdCrossed handler that writes marker file for test validation.
BDD Test Scenarios & Steps
Bdd/features/capacity_threshold.feature, Bdd/features/steps/syslog_steps.py, Bdd/features/environment.py
New feature file with two scenarios: one verifying callback fires when usage crosses threshold, another verifying no callback when usage stays below. Step implementations wire --capacity-threshold CLI argument, enable threshold via context, and assert callback invocation via filesystem marker checks. Teardown cleanup removes threshold marker file.
Unit Tests
Tests/SolidSyslogFileStoreTest.cpp
Comprehensive test suite covering: rising-edge firing, single-fire while above threshold, re-arming after drop via discard, suppression when zero/NULL, context propagation, ordering with store-full callback under HALT, sticky 100% behavior, dynamic threshold change, and persistence/resume scenarios. Total 283 lines of new test code.
Documentation
DEVLOG.md, CLAUDE.md, docs/iec62443.md
DEVLOG.md records implementation decisions (BlockSequence ownership, byte-based threshold, edge-triggered semantics, sticky-bit sequencing, marker-file validation approach). CLAUDE.md updates public API surface documentation. docs/iec62443.md clarifies CR 2.9/CR 2.10 compliance with callback ordering (threshold before discard/halt).

Sequence Diagram

sequenceDiagram
    actor App as Application
    participant CLI as ExampleCommandLine
    participant Store as FileStore
    participant BS as BlockSequence
    participant CB as Callback

    App->>CLI: Parse --capacity-threshold 5000
    CLI->>CLI: Store threshold in options
    
    App->>Store: Create with threshold config
    Store->>BS: Initialize with getCapacityThreshold,<br/>onThresholdCrossed
    
    Note over BS: Resume stored data<br/>Check if usage ≥ threshold
    alt Usage already above threshold
        BS->>CB: Fire onThresholdCrossed
    end

    App->>Store: Write message
    Store->>BS: Prepare and write
    
    Note over BS: On each Write:
    BS->>BS: Query getCapacityThreshold()
    BS->>BS: Compare current usage<br/>vs threshold
    
    alt Usage crosses threshold upward
        BS->>BS: Set thresholdCrossed=true
        BS->>CB: Invoke onThresholdCrossed
    end
    
    alt Store becomes full
        BS->>CB: Later: Invoke onStoreFull<br/>(after threshold)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • #239: Prior refactor that introduced BlockSequence scaffolding, capacity getters (GetTotalBytes, GetUsedBytes), and migrated SolidSyslogStoreFullCallback—direct prerequisites for this feature.
  • #107: Implements the terminal onStoreFull callback; this PR explicitly defines the firing order and interaction between threshold and store-full notifications on the same Write.
  • #103: Implements file-rotation and discard-policy logic in SolidSyslogFileStore; this PR's threshold re-arming depends on discard operations touching the same write-path code.

Poem

🐰 A threshold so clever, it whispers with care,
"The store is near full, alert the whole square!"
Before bytes do crumble or silence calls halt,
The rabbit hops gleefully—no data was lost! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.55% 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(filestore): configurable capacity threshold alert (S05.09)' clearly and concisely describes the main feature addition—a configurable capacity threshold alert for the file store—following Conventional Commits format.
Description check ✅ Passed The PR description covers all key sections: a comprehensive summary of API additions and behavior semantics, detailed test plan with specific test counts and criteria, areas affected (core interfaces, block sequence logic, example wiring, BDD features), and references to the requirement closure.
Linked Issues check ✅ Passed The PR comprehensively addresses all coding requirements from issue #111: API typedefs and config fields added to SolidSyslogFileStoreConfig [#111]; edge-triggered firing with latch and re-arm logic implemented [#111]; NULL/zero disabling handled [#111]; ordering with onStoreFull guaranteed [#111]; startup firing on Create implemented [#111]; BDD scenarios for fire, no-fire, and ordering added [#111]; documentation and example wiring complete [#111].
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the configurable capacity threshold alert: API surface, core logic in BlockSequence, example integration, BDD test coverage, and documentation updates—all aligned with issue #111 requirements and prerequisites from S18.01.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/capacity-threshold-alert

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@github-actions

github-actions Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 972 passed, 🙈 3 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 921 passed, 🙈 3 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 921 passed, 🙈 3 skipped)
   🚦   integration-linux-openssl: 100% successful (✔️ 9 passed)
   🚦   bdd-linux-syslog-ng: 100% successful (✔️ 44 passed)
   🚦   bdd-windows-otel: 59% successful (✔️ 26 passed, 🙈 18 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 834 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


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

@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: 1

🧹 Nitpick comments (1)
Core/Interface/SolidSyslogFileStore.h (1)

26-30: ⚡ Quick win

Add re-arm behavior to the typedef comment.

The current doc says "fires once when used-bytes transitions from below threshold to at-or-above" but omits that the callback re-arms when usage subsequently falls back below the threshold. An integrator could reasonably read "fires once" as a lifetime guarantee rather than a per-rising-edge guarantee.

✏️ Proposed wording addition
 /* Edge-triggered: fires once when used-bytes transitions from below threshold to at-or-above.
+ * Re-arms automatically when usage falls back below the threshold, so the callback can fire
+ * again on the next rising-edge transition.
  * NullBuffer note: SolidSyslog_Log is synchronous under SolidSyslogNullBuffer, so calling
  * SolidSyslog_Log from this callback will recurse into Store_Write. Either gate the Log,
  * or use SolidSyslogPosixMessageQueueBuffer (which returns immediately). */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Core/Interface/SolidSyslogFileStore.h` around lines 26 - 30, Update the
typedef comment for SolidSyslogStoreThresholdCallback to clarify that the
callback is edge-triggered on rising transitions of used-bytes (fires each time
usage goes from below threshold to at-or-above) and that it is re-armed when
usage later falls back below the threshold (i.e., it will fire again on
subsequent rising edges); keep the existing NullBuffer note and gating advice
intact but adjust wording to avoid implying a single lifetime invocation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/iec62443.md`:
- Line 35: Tiny wording fix: update the description for
SolidSyslogStoreThresholdFunction + SolidSyslogStoreThresholdCallback to read
"re-arms when usage falls back below the threshold" (i.e., insert "the
threshold" after "falls back below") so the behavior sentence is explicit and
unambiguous for readers.

---

Nitpick comments:
In `@Core/Interface/SolidSyslogFileStore.h`:
- Around line 26-30: Update the typedef comment for
SolidSyslogStoreThresholdCallback to clarify that the callback is edge-triggered
on rising transitions of used-bytes (fires each time usage goes from below
threshold to at-or-above) and that it is re-armed when usage later falls back
below the threshold (i.e., it will fire again on subsequent rising edges); keep
the existing NullBuffer note and gating advice intact but adjust wording to
avoid implying a single lifetime invocation.
🪄 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: 16694224-0a08-4add-9223-1e918dee0992

📥 Commits

Reviewing files that changed from the base of the PR and between 488701a and 8a70d98.

📒 Files selected for processing (14)
  • Bdd/features/capacity_threshold.feature
  • Bdd/features/environment.py
  • Bdd/features/steps/syslog_steps.py
  • CLAUDE.md
  • Core/Interface/SolidSyslogFileStore.h
  • Core/Source/BlockSequence.c
  • Core/Source/BlockSequence.h
  • Core/Source/SolidSyslogFileStore.c
  • DEVLOG.md
  • Example/Common/ExampleCommandLine.c
  • Example/Common/ExampleCommandLine.h
  • Example/Threaded/main.c
  • Tests/SolidSyslogFileStoreTest.cpp
  • docs/iec62443.md

Comment thread docs/iec62443.md
@DavidCozens DavidCozens merged commit 1651d57 into main May 2, 2026
14 checks passed
@DavidCozens DavidCozens deleted the feat/capacity-threshold-alert branch May 2, 2026 19:43
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.

S05.09: Configurable capacity threshold alert

1 participant