Parent epic: #268 (S08.03 — UDP syslog from FreeRTOS reaches the oracle)
Background
S08.03 slice 5 (#305) landed the FreeRTOS BDD harness and tagged eight @udp features with @freertoswip so the new bdd-freertos-qemu job could go green on a single passing scenario. Slice 4 (#303) shipped the set NAME VALUE interactive command channel that mutates the FreeRTOS example's identity, transport endpoint, and PRIVAL fields in-RAM. The two pieces compose: the BDD driver can now drive the FreeRTOS example into any configuration the existing Linux scenarios need, but the bridge — translating --flag VALUE cmdline pairs into set NAME VALUE UART writes — does not yet exist. Today target_driver.spawn_example_process raises NotImplementedError whenever extra_args is non-empty under BDD_TARGET=freertos.
Scope
Add the cmdline -> set translation in the FreeRTOS branch of the BDD target driver, loosen the FreeRTOS example's OnSet facility/severity input validation to match Linux's permissive atoi-and-cast, and untag every @udp scenario that the combination unblocks.
Translation table (exactly four entries; no premature generalisation):
| Cmdline flag |
FreeRTOS interactive command |
--facility N |
set facility N |
--severity N |
set severity N |
--msgid X |
set msgid X |
--message X |
set msg X |
These are all the flags that @udp features currently pass to run_example. Any other flag must raise from the driver so a misconfigured scenario fails loudly with a clear Python traceback rather than silently no-op'ing or hitting a confusing set rejection.
Design
- Spawn (
target_driver.spawn_example_process): on FreeRTOS, no longer raises on non-empty extra_args; QEMU argv is unchanged.
- New helper
target_driver.apply_extra_args(context, process, extra_args) called by _run_with_prompt_protocol immediately after wait_for_prompt(process). On Linux/Windows it is a no-op (flags already in argv from spawn). On FreeRTOS it walks the extra_args list pairwise, looks each --flag up in the translation table, and writes one set NAME VALUE\n line per pair to process.stdin. An unknown flag, an odd-length args list, or a value missing from the table raises with the offending flag in the message.
Example/FreeRtos/SingleTask/main.c::OnSet: drop the parsed > 23U (facility) and parsed > 7U (severity) upper-bound rejections. This matches Linux's atoi-and-cast — the example becomes permissive about the value and the library is the single authority on what's valid (the library encodes out-of-range facility/severity as the internal-error PRIVAL 43).
- The cmdline
--message ↔ FreeRTOS set msg naming gap stays in the table; the example global is g_msg (Example/FreeRtos/SingleTask/main.c#L100) and renaming the FreeRTOS-side command would churn the example for cosmetic gain.
Two-commit plan (single PR, single issue)
Strict TDD: untag, run red, write minimum translation, run green, commit. Repeat.
Commit A — feat: S08.03 slice 6a apply_extra_args helper + facility/severity translation
- New
apply_extra_args helper covering only --facility / --severity.
_run_with_prompt_protocol call site.
target_driver.spawn_example_process no longer raises on FreeRTOS extra_args.
OnSet loosened for facility/severity (drop upper-bound rejection).
- Untag
prival.feature (drop the feature-level @freertoswip). All six scenarios — including the two Out-of-range scenarios — should pass against syslog-ng-freertos.
Commit B — feat: S08.03 slice 6b msgid/msg translation, untag message_fields + udp_mtu
- Extend translation table with
--msgid and --message.
- Untag
message_fields.feature::Message ID appears in the message and ::Message body appears in the message. The third scenario (Complete RFC 5424 message with all fields) stays tagged — it asserts system hostname / current timestamp / process PID, which slice 6 alone cannot satisfy.
- Untag
udp_mtu.feature::Full delivery of a UTF-8 message within the path MTU. The oversize scenario stays @windows_wip (orthogonal to FreeRTOS).
Out of scope
Acceptance
References
- DEVLOG 2026-05-09 slice 5 entry — full per-feature
@freertoswip rationale and the originally-suggested follow-up ordering.
Bdd/features/steps/target_driver.py — current NotImplementedError raise site.
Bdd/features/steps/syslog_steps.py::_run_with_prompt_protocol — call-site for apply_extra_args.
Example/FreeRtos/SingleTask/main.c::OnSet — FreeRTOS-side set handler (target of the translated commands; the upper-bound loosening is the only C-side touch).
Parent epic: #268 (S08.03 — UDP syslog from FreeRTOS reaches the oracle)
Background
S08.03 slice 5 (#305) landed the FreeRTOS BDD harness and tagged eight
@udpfeatures with@freertoswipso the newbdd-freertos-qemujob could go green on a single passing scenario. Slice 4 (#303) shipped theset NAME VALUEinteractive command channel that mutates the FreeRTOS example's identity, transport endpoint, and PRIVAL fields in-RAM. The two pieces compose: the BDD driver can now drive the FreeRTOS example into any configuration the existing Linux scenarios need, but the bridge — translating--flag VALUEcmdline pairs intoset NAME VALUEUART writes — does not yet exist. Todaytarget_driver.spawn_example_processraisesNotImplementedErrorwheneverextra_argsis non-empty underBDD_TARGET=freertos.Scope
Add the cmdline -> set translation in the FreeRTOS branch of the BDD target driver, loosen the FreeRTOS example's
OnSetfacility/severity input validation to match Linux's permissiveatoi-and-cast, and untag every@udpscenario that the combination unblocks.Translation table (exactly four entries; no premature generalisation):
--facility Nset facility N--severity Nset severity N--msgid Xset msgid X--message Xset msg XThese are all the flags that
@udpfeatures currently pass torun_example. Any other flag must raise from the driver so a misconfigured scenario fails loudly with a clear Python traceback rather than silently no-op'ing or hitting a confusingsetrejection.Design
target_driver.spawn_example_process): on FreeRTOS, no longer raises on non-emptyextra_args; QEMU argv is unchanged.target_driver.apply_extra_args(context, process, extra_args)called by_run_with_prompt_protocolimmediately afterwait_for_prompt(process). On Linux/Windows it is a no-op (flags already in argv from spawn). On FreeRTOS it walks theextra_argslist pairwise, looks each--flagup in the translation table, and writes oneset NAME VALUE\nline per pair toprocess.stdin. An unknown flag, an odd-length args list, or a value missing from the table raises with the offending flag in the message.Example/FreeRtos/SingleTask/main.c::OnSet: drop theparsed > 23U(facility) andparsed > 7U(severity) upper-bound rejections. This matches Linux'satoi-and-cast — the example becomes permissive about the value and the library is the single authority on what's valid (the library encodes out-of-range facility/severity as the internal-error PRIVAL 43).--message↔ FreeRTOSset msgnaming gap stays in the table; the example global isg_msg(Example/FreeRtos/SingleTask/main.c#L100) and renaming the FreeRTOS-side command would churn the example for cosmetic gain.Two-commit plan (single PR, single issue)
Strict TDD: untag, run red, write minimum translation, run green, commit. Repeat.
Commit A —
feat: S08.03 slice 6a apply_extra_args helper + facility/severity translationapply_extra_argshelper covering only--facility/--severity._run_with_prompt_protocolcall site.target_driver.spawn_example_processno longer raises on FreeRTOSextra_args.OnSetloosened for facility/severity (drop upper-bound rejection).prival.feature(drop the feature-level@freertoswip). All six scenarios — including the twoOut-of-rangescenarios — should pass againstsyslog-ng-freertos.Commit B —
feat: S08.03 slice 6b msgid/msg translation, untag message_fields + udp_mtu--msgidand--message.message_fields.feature::Message ID appears in the messageand::Message body appears in the message. The third scenario (Complete RFC 5424 message with all fields) stays tagged — it asserts system hostname / current timestamp / process PID, which slice 6 alone cannot satisfy.udp_mtu.feature::Full delivery of a UTF-8 message within the path MTU. The oversize scenario stays@windows_wip(orthogonal to FreeRTOS).Out of scope
syslog.feature(the single scenario),header_fields.feature::Hostnameand::Process ID, andmessage_fields.feature::Complete RFC 5424 message: assert system identity / current time. These cannot be unblocked by slice 6 alone — they need a follow-up to either driveset hostname/set procidfrom the BDD step (and a real clock for timestamp) or loosen the assertions on FreeRTOS targets. Tracked under epic S08.03: UDP syslog from FreeRTOS reaches the oracle #268.Acceptance
behave-freertosagainstsyslog-ng-freertosrunsprival.feature(6 scenarios),message_fields.feature::Message ID,::Message body, andudp_mtu.feature::Full delivery within path MTUall green; the residual@freertoswipcount drops by these scenarios.behave-linuxregression: full Linux suite remains green (no behaviour change on Linux/Windows targets).References
@freertoswiprationale and the originally-suggested follow-up ordering.Bdd/features/steps/target_driver.py— currentNotImplementedErrorraise site.Bdd/features/steps/syslog_steps.py::_run_with_prompt_protocol— call-site forapply_extra_args.Example/FreeRtos/SingleTask/main.c::OnSet— FreeRTOS-sidesethandler (target of the translated commands; the upper-bound loosening is the only C-side touch).