Skip to content

feat: S08.10 tcp_reconnect BDD scenario green on FreeRTOS QEMU#342

Merged
DavidCozens merged 3 commits into
mainfrom
feat/s08-10-tcp-reconnect
May 11, 2026
Merged

feat: S08.10 tcp_reconnect BDD scenario green on FreeRTOS QEMU#342
DavidCozens merged 3 commits into
mainfrom
feat/s08-10-tcp-reconnect

Conversation

@DavidCozens

@DavidCozens DavidCozens commented May 11, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #339. Second slice of S08.06 (TCP transport on FreeRTOS-Plus-TCP) — a verification slice on top of the S08.09 adapter + SwitchingSender:

  • Split @buffered into @buffered + @store. Earlier the tag meant both "uses the long-lived interactive process" and "needs a file-backed store"; the FreeRTOS compose filter not @buffered then excluded tcp_reconnect.feature even though it doesn't need a file store. @buffered keeps the interactive-process meaning; @store marks the file-store dependency. tcp_reconnect.feature is @tcp @buffered (no @store) so the FreeRTOS filter admits it.
  • Route start_bdd_target_process through target_driver. The one-shot path already abstracted native-vs-QEMU and argv-vs-UART; the interactive path bypassed it with a parallel subprocess.Popen. Unifying both means QEMU + set transport tcp over the UART falls out for free on FreeRTOS, and future embedded platforms extend one branch point instead of two.
  • SendClosesSocketOnFailure already covered by S08.09's SendClosesSocketOnError (plus SendClosesSocketOnShortWrite and ReadReturnsNegativeOneOnErrorAndClosesSocket, all using CHECK_SOCKET_CLOSED_ONCE). The close-on-failure contract that makes reconnect possible is already pinned by three tests — no additional unit test added.

Test plan

  • cmake --preset debug && ctest — 8/8 host suites green (incl. SolidSyslogFreeRtosTcpStreamTest 39 tests).
  • cmake --preset freertos-cross && cmake --build --preset freertos-cross --target SolidSyslogBddTarget — clean cross build.
  • QEMU smoke: set transport tcp followed by repeated send then quit exits cleanly via the UART — interactive task survives the SwitchingSender flip + Service-task retry storm against no listener.
  • bdd-freertos-qemu CI job — the docker-side syslog-ng config swap is the real arbiter (can't be run locally; outside compose it breaks docker networking).
  • No regression in bdd-linux-syslog-ng (tag rename touches @store features; Linux filter still admits them).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Reorganized BDD test scenarios with updated tag classifications for improved test execution and organization.
    • Refactored test framework infrastructure to standardize initialization and execution of test targets across scenarios.
    • Updated test execution configuration to support new test categorization strategy.
  • Documentation

    • Added development log entry documenting recent BDD testing improvements and framework changes.

Review Change Stack

DavidCozens and others added 2 commits May 11, 2026 19:15
Split @Buffered into @Buffered (interactive process) + @store (file-
backed store) so the FreeRTOS compose filter admits tcp_reconnect
without dragging in store_and_forward / capacity_threshold /
store_capacity / block_lifecycle / power_cycle_replay. Route the
buffered-interactive spawn through target_driver so QEMU plus
`set transport tcp` over the UART falls out for free on FreeRTOS;
Linux/Windows argv path unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 11, 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 53 minutes and 49 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: 5a3ba216-f71e-4a0b-91bf-53a315f67f92

📥 Commits

Reviewing files that changed from the base of the PR and between f169c90 and 6c46c0a.

📒 Files selected for processing (1)
  • Bdd/features/steps/syslog_steps.py
📝 Walkthrough

Walkthrough

Refactors buffered BDD target process startup by extracting configuration flag building into a build_buffered_extra_args helper, rerouting initialization through target_driver.spawn_example_process, adding @store tags to five feature files, updating CI tag filtering from @buffered to @store exclusion for FreeRTOS, and documenting the tcp_reconnect scenario in DEVLOG.

Changes

Buffered BDD Target Startup Refactoring with Store-Tag Integration

Layer / File(s) Summary
Process Startup Refactoring
Bdd/features/steps/syslog_steps.py
Removes subprocess import and replaces direct command construction with build_buffered_extra_args(context, transport, no_sd=False) to generate transport/store/capacity/message flags. Updates start_bdd_target_process(context, extra_args) signature to accept extra_args and spawn via target_driver.spawn_example_process, wait for prompt, then apply extra args interactively.
Feature Store-Capability Tags
Bdd/features/block_lifecycle.feature, Bdd/features/capacity_threshold.feature, Bdd/features/power_cycle_replay.feature, Bdd/features/store_and_forward.feature, Bdd/features/store_capacity.feature
Five feature files tagged with @store to denote store-and-forward or capacity-threshold dependencies (e.g., @tcp @Buffered @store``). One feature adds @tcp alongside existing `@buffered` and `@store` tags.
Step Bindings Update
Bdd/features/steps/syslog_steps.py
Three transport-scoped "given" steps updated to call start_bdd_target_process(context, build_buffered_extra_args(...)) instead of constructing subprocess commands, incorporating the new refactored startup flow for both default and no-structured-data variants.
CI Configuration and Development Log
ci/docker-compose.bdd.yml, DEVLOG.md
Docker Compose behave-freertos service changes tag filter from not @Buffered to `not `@store to exclude file-backed store scenarios on FreeRTOS. DEVLOG entry (2026-05-11) documents S08.10 tcp_reconnect scenario, tagging decision (@buffered + @store split), and routing of start_bdd_target_process through target_driver.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • DavidCozens/solid-syslog#339: This PR directly implements the acceptance criteria for the tcp_reconnect BDD scenario on QEMU by refactoring the buffered target startup harness and tagging features with @store to control test selection on FreeRTOS.

Possibly related PRs

  • DavidCozens/solid-syslog#341: Both PRs modify syslog_steps.py to build and pass extra_args through target_driver.spawn_example_process/apply_extra_args and adjust CI tag filters for test selection.
  • DavidCozens/solid-syslog#307: Both PRs update the BDD interactive startup flow to route process initialization and configuration through target_driver helpers.
  • DavidCozens/solid-syslog#154: Both PRs refactor syslog_steps.py to change how the BDD target process is started and driven via interactive protocol and step bindings.

Poem

🐰 The target springs to life with args in tow,
Store tags dance where features flow,
CI gates refresh to know,
What FreeRTOS can bestow—
Reconnect shines bright, a rabbit's glow! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 accurately summarizes the main objective: making the tcp_reconnect BDD scenario pass on FreeRTOS QEMU, which is the core purpose of this PR.
Description check ✅ Passed The description covers purpose (closes #339), change details (tag split, routing refactor), and test evidence, but lacks an explicit 'Areas Affected' section per the template.
Linked Issues check ✅ Passed The PR delivers all primary coding objectives from #339: splits @buffered/@store tags, routes start_bdd_target_process through target_driver, confirms SendClosesSocketOnFailure coverage via existing tests, and achieves tcp_reconnect.feature green on QEMU per test plan.
Out of Scope Changes check ✅ Passed All changes align with #339 scope: feature files updated for tag split, BDD steps refactored to use target_driver, docker-compose filter adjusted, and DEVLOG documented. No out-of-scope additions 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 feat/s08-10-tcp-reconnect

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.

@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1111 passed, 🙈 3 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 1063 passed, 🙈 3 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1063 passed, 🙈 3 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: 57% successful (✔️ 28 passed, 🙈 21 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 975 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: 2

🤖 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 `@Bdd/features/steps/syslog_steps.py`:
- Around line 507-514: The current truthy getattr checks when building extra
args drop explicit zero values (e.g., --capacity-threshold 0); update the checks
for numeric fields store_max_blocks, store_max_block_size, and
capacity_threshold to use "is not None" (e.g., getattr(context,
'store_max_blocks', None) is not None) so zero is preserved when appending to
args, while keeping the existing truthy check for the string field
store_discard_policy as-is.

In `@DEVLOG.md`:
- Around line 129-155: Replace the literal asterisk-number tokens that are being
parsed as emphasis (e.g. "*40", "*48", the sequence "*16 → *32 → *40 → *48", and
any occurrences in "SOLIDSYSLOG_*_SIZE") with their code-literal form by
wrapping them in backticks (or escaping the asterisks) so the markdown renders
them as literal tokens; update the DEVLOG.md instances that mention the stack
budgets and the "project_freertos_stack_budget" rename accordingly.
🪄 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: 45cea966-fe27-45dd-9290-554c25a5afaf

📥 Commits

Reviewing files that changed from the base of the PR and between 010f491 and f169c90.

📒 Files selected for processing (8)
  • Bdd/features/block_lifecycle.feature
  • Bdd/features/capacity_threshold.feature
  • Bdd/features/power_cycle_replay.feature
  • Bdd/features/steps/syslog_steps.py
  • Bdd/features/store_and_forward.feature
  • Bdd/features/store_capacity.feature
  • DEVLOG.md
  • ci/docker-compose.bdd.yml

Comment thread Bdd/features/steps/syslog_steps.py Outdated
Comment thread DEVLOG.md
Comment on lines +129 to +155
- **InteractiveTask stack *40 → *48.** StreamSender.Connect allocates
a SolidSyslogAddressStorage plus a SolidSyslogFormatter sized for
SOLIDSYSLOG_MAX_HOST_SIZE on stack; TransmitFramed adds a small
octet-prefix formatter. Empirically tipped a *40 budget into a
Cortex-M lockup (PC=0, fault-during-fault — classic
stack-overflow-corrupting-the-exception-return signature) when
SwitchingSender flipped UDP→TCP→UDP across repeated sends. *48
restored ~4 KB headroom and the same scenario completed cleanly.
- **Test fixture: openStream() / readIntoBuffer() helpers and a
CHECK_SOCKET_CLOSED_ONCE macro.** The arrange step in 25+ tests
collapses to `openStream();`. The macro pins both the closesocket
call count *and* the identity of the closed socket — applying it
uniformly across the close-on-failure tests caught three sites
(SendClosesSocketOnError, ReadReturnsNegativeOneOnErrorAndClosesSocket,
DestroyClosesOpenSocket) that previously only checked the count.
The check count went 56 → 59 from that tightening alone.

### Deferred

- **CMake-driven memory scaling** for both static-`_Create` storage
sizes and FreeRTOS task stack depths. The recurring stack bumps
(*16 → *32 → *40 → *48) and the per-class `SOLIDSYSLOG_*_SIZE`
macros point to this as the right next intervention: expose them as
CMake-tunable variables so integrators size memory once,
declaratively, instead of editing `main.c` each time a new feature
lands. Captured in memory `project_freertos_stack_budget` (renamed
from *40 to *48 ceiling).

@coderabbitai coderabbitai Bot May 11, 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 malformed emphasis markers in stack-size text.

The *N tokens are being parsed as emphasis and trigger markdownlint MD037 warnings (Line 135, Line 150, Line 155). Wrap these values in backticks (or escape *) to keep the intended literal text.

Suggested patch
-- **InteractiveTask stack *40 → *48.** StreamSender.Connect allocates
+- **InteractiveTask stack `*40` → `*48`.** StreamSender.Connect allocates

-  (*16 → *32 → *40 → *48) and the per-class `SOLIDSYSLOG_*_SIZE`
+  (`*16` → `*32` → `*40` → `*48`) and the per-class `SOLIDSYSLOG_*_SIZE`

-  from *40 to *48 ceiling).
+  from `*40` to `*48` ceiling).
📝 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
- **InteractiveTask stack *40 → *48.** StreamSender.Connect allocates
a SolidSyslogAddressStorage plus a SolidSyslogFormatter sized for
SOLIDSYSLOG_MAX_HOST_SIZE on stack; TransmitFramed adds a small
octet-prefix formatter. Empirically tipped a *40 budget into a
Cortex-M lockup (PC=0, fault-during-fault — classic
stack-overflow-corrupting-the-exception-return signature) when
SwitchingSender flipped UDP→TCP→UDP across repeated sends. *48
restored ~4 KB headroom and the same scenario completed cleanly.
- **Test fixture: openStream() / readIntoBuffer() helpers and a
CHECK_SOCKET_CLOSED_ONCE macro.** The arrange step in 25+ tests
collapses to `openStream();`. The macro pins both the closesocket
call count *and* the identity of the closed socket — applying it
uniformly across the close-on-failure tests caught three sites
(SendClosesSocketOnError, ReadReturnsNegativeOneOnErrorAndClosesSocket,
DestroyClosesOpenSocket) that previously only checked the count.
The check count went 56 → 59 from that tightening alone.
### Deferred
- **CMake-driven memory scaling** for both static-`_Create` storage
sizes and FreeRTOS task stack depths. The recurring stack bumps
(*16 → *32 → *40 → *48) and the per-class `SOLIDSYSLOG_*_SIZE`
macros point to this as the right next intervention: expose them as
CMake-tunable variables so integrators size memory once,
declaratively, instead of editing `main.c` each time a new feature
lands. Captured in memory `project_freertos_stack_budget` (renamed
from *40 to *48 ceiling).
- **InteractiveTask stack `*40``*48`.** StreamSender.Connect allocates
a SolidSyslogAddressStorage plus a SolidSyslogFormatter sized for
SOLIDSYSLOG_MAX_HOST_SIZE on stack; TransmitFramed adds a small
octet-prefix formatter. Empirically tipped a *40 budget into a
Cortex-M lockup (PC=0, fault-during-fault — classic
stack-overflow-corrupting-the-exception-return signature) when
SwitchingSender flipped UDP→TCP→UDP across repeated sends. *48
restored ~4 KB headroom and the same scenario completed cleanly.
- **Test fixture: openStream() / readIntoBuffer() helpers and a
CHECK_SOCKET_CLOSED_ONCE macro.** The arrange step in 25+ tests
collapses to `openStream();`. The macro pins both the closesocket
call count *and* the identity of the closed socket — applying it
uniformly across the close-on-failure tests caught three sites
(SendClosesSocketOnError, ReadReturnsNegativeOneOnErrorAndClosesSocket,
DestroyClosesOpenSocket) that previously only checked the count.
The check count went 56 → 59 from that tightening alone.
### Deferred
- **CMake-driven memory scaling** for both static-`_Create` storage
sizes and FreeRTOS task stack depths. The recurring stack bumps
(`*16``*32``*40``*48`) and the per-class `SOLIDSYSLOG_*_SIZE`
macros point to this as the right next intervention: expose them as
CMake-tunable variables so integrators size memory once,
declaratively, instead of editing `main.c` each time a new feature
lands. Captured in memory `project_freertos_stack_budget` (renamed
from `*40` to `*48` ceiling).
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 135-135: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


[warning] 150-150: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


[warning] 150-150: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


[warning] 155-155: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)

🤖 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` around lines 129 - 155, Replace the literal asterisk-number tokens
that are being parsed as emphasis (e.g. "*40", "*48", the sequence "*16 → *32 →
*40 → *48", and any occurrences in "SOLIDSYSLOG_*_SIZE") with their code-literal
form by wrapping them in backticks (or escaping the asterisks) so the markdown
renders them as literal tokens; update the DEVLOG.md instances that mention the
stack budgets and the "project_freertos_stack_budget" rename accordingly.

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.

Declining — those *40/*48/*16 tokens are in the S08.09 DEVLOG entry (commit 712bde8, PR #341, already merged) which this PR does not touch. Per the project SKILL.md convention "Never rewrite history. Always append.", historical DEVLOG entries are not edited even to fix lint warnings. The S08.10 entry added in this PR doesn't use bare *N tokens, so no new lint warnings are introduced. Future entries will avoid the pattern (use backticks around \*N`` or call them out as e.g. "INTERACTIVE_TASK_STACK_DEPTH = configMINIMAL_STACK_SIZE * 48").

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 Acknowledged — makes sense to keep history immutable per SKILL.md. I’ve double-checked: the S08.10 DEVLOG chunk in this PR doesn’t introduce any bare “*N” tokens, so no new MD037 warnings are added.

If you’d like to silence the legacy warnings without touching prior entries, we can:

  • Add DEVLOG.md to markdownlint-cli2 ignores (repo-wide), or
  • Add a rule override for MD037 scoped to DEVLOG.md.

Happy to open a tiny follow-up PR either way; just say which option you prefer (or leave as-is).


✏️ Learnings added
Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 342
File: DEVLOG.md:129-155
Timestamp: 2026-05-11T19:55:23.240Z
Learning: Do not edit historical DEVLOG entries; follow SKILL.md “Never rewrite history. Always append.” For future DEVLOG entries, avoid bare *N tokens; use backticks (e.g., `*48`) or explicit expressions instead.

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.

`--capacity-threshold 0` is the documented "disable" sentinel for
SolidSyslogStoreThresholdFunction; truthy-coerce would silently drop it.
No scenario passes 0 today but the bug is latent in the helper.
CodeRabbit catch on #342.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1111 passed, 🙈 3 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 1063 passed, 🙈 3 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1063 passed, 🙈 3 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: 57% successful (✔️ 28 passed, 🙈 21 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 975 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.

@DavidCozens DavidCozens merged commit 51ce394 into main May 11, 2026
19 checks passed
@DavidCozens DavidCozens deleted the feat/s08-10-tcp-reconnect branch May 11, 2026 19:58
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.

S08.10: tcp_reconnect BDD scenario green on QEMU

1 participant