Skip to content

feat: spool records to a file store with a CRC-16 at rest - #10

Merged
DavidCozens merged 1 commit into
mainfrom
stage-10-file-store
Aug 16, 2026
Merged

feat: spool records to a file store with a CRC-16 at rest#10
DavidCozens merged 1 commit into
mainfrom
stage-10-file-store

Conversation

@DavidCozens

Copy link
Copy Markdown
Contributor

Spool to a SolidSyslogBlockStore over a SolidSyslogFileBlockDevice over the library's FatFs
port, replacing the Null store. The service task drains the ring into storage and sends from there,
so a failed send costs a retry rather than the record: the audit trail survives an outage instead of
ending at it.

#define SYSLOG_STORE_PREFIX "syslog"
#define SYSLOG_STORE_BLOCKS 4U

struct SolidSyslogBlockStoreConfig storeConfig = {
    .BlockDevice    = SolidSyslogFileBlockDevice_Create(SolidSyslogFatFsFile_Create(), SYSLOG_STORE_PREFIX, 0U),
    .MaxBlocks      = SYSLOG_STORE_BLOCKS,
    .DiscardPolicy  = SOLIDSYSLOG_DISCARD_POLICY_OLDEST,
    .SecurityPolicy = SolidSyslogCrc16Policy_Create(),
};

Three decisions come with it: how much to store, which is capacity on the medium rather than RAM;
what happens when it fills — discard oldest, discard newest, or halt; and whether to be warned
before that point, via the capacity-threshold callback.

This device stores four blocks, one file per block, syslog00.log upward on the volume it already
mounts, and discards the oldest when full.

The CRC-16 detects corruption, not tampering. It catches a truncated write or bit-rot; anyone who
can edit a stored record can recompute it. It establishes that a record came back the way it went
in, which is the prerequisite for spooling at all. Making stored records tamper-evident, and then
unreadable, are later stages.

Storing happens on the service task, so a task that calls SolidSyslog_Log still knows nothing
about what happens after it returns and its stack does not move. The RAM is pool allocation and
handles rather than buffers — nothing holds a block in memory, so the store costs its handles
rather than its capacity.

FatFs joins SOLIDSYSLOG_PLATFORMS, and its sources compile against this device's own ffconf.h
like the rest of the application.

When you need it. If losing the records raised during an outage is not acceptable, or if they
must survive a reboot.

@DavidCozens

Copy link
Copy Markdown
Contributor Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d2df1355-1ec6-4e61-94fa-9b8dac0b65da

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

@DavidCozens
DavidCozens force-pushed the stage-09-time-quality branch from 4991869 to 0b96bbd Compare August 16, 2026 21:49
A SolidSyslogBlockStore over a FileBlockDevice over the library's FatFs port,
replacing the Null store. The service task drains the ring into the store and
sends from there, so a failed send costs a retry rather than the record: the
audit trail survives an outage instead of ending at it.

  Flash      +11,596 B  (+3,952 on the previous stage)
  RAM         +9,124 B    (+1,436)
  Log stack     +672 B  (unchanged)
  Service       +960 B       (+64)

The log stack does not move: storing happens on the service task, and a task that
calls Log still knows nothing about what happens after it returns. The service
task's own high-water rises 64 bytes, which its existing allocation absorbs.

The static RAM is pool allocation, not buffers. The block size is file capacity —
nothing holds a block in memory, so the store costs its handles rather than its
capacity.

CRC-16 detects corruption, not tampering: it catches a truncated write or bit-rot,
and anyone who can edit a stored record can recompute it. It establishes that a
record came back the way it went in, which is the prerequisite for spooling at
all. Making stored records tamper-evident, and then unreadable, are later stages.

Three decisions come with the store — capacity, what happens when it fills, and
whether to be warned before that point. This device stores four blocks, one file
per block, syslog00.log upward on the volume it already mounts, and discards the
oldest when full.

FatFs joins SOLIDSYSLOG_PLATFORMS. Its sources take the application's flags and
include set, so they compile against this device's own ffconf.h.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@DavidCozens
DavidCozens changed the base branch from stage-09-time-quality to main August 16, 2026 21:49
@DavidCozens
DavidCozens merged commit 780b3bf into main Aug 16, 2026
@DavidCozens
DavidCozens deleted the stage-10-file-store branch August 16, 2026 21:54
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.

1 participant