Skip to content

examples: Functional Blocks report through the Observatory; host programs may print by rule - #188

Merged
ritzylab-dev merged 4 commits into
devfrom
fix/example-fbs-observatory
Nov 5, 2026
Merged

ritzylab-dev merged 4 commits into
devfrom
fix/example-fbs-observatory

Conversation

@ritzylab-dev

@ritzylab-dev ritzylab-dev commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

The gap

Three example Functional Blocks printed to stdout — the one thing the rules say an FB must never do, because the same FB
must run on targets with no console. The layer-call checker did not scan examples/, so the showcase code was exempt from
the rule it is meant to demonstrate.

What changed and why it fixes it

One application-defined Observatory event, EMBEDIQ_OBS_EVT_APP, with the meaning of its code and value documented by the
emitting FB. Every former print is now such an event; the demos show their trace through the STDOUT transport, and each
README says how to read it. The checker scans examples/ and allows stdio and delays only for the four host entry
programs, by exact path and rule — every other rule still applies to them.

A sub-function receives the payload bytes only — no message id, length or source endpoint. fb_north_bridge,
fb_policy_engine and fb_env_sim read those bytes as a message envelope: the north bridge never sent or buffered a
reading (the flush reported 0 records), the policy engine read the wrong bytes, and a cloud command was never applied.
Each now reads its payload directly, and the north bridge has one sub-function per message type. Since no source endpoint
is available, per-sensor north-bridge events carry the sensor id in the code (base + sensor id) with target 0xFF.

The payload contract is now stated where it is used. The embediq_subfn_run_fn typedef says what msg is: a borrowed
pointer to the message's payload bytes, read through its defined layout with memcpy, never NULL in engine dispatch, and
possibly NULL under direct test delivery. The same text is rule R-sub-34 in CODING_RULES.md, with a pointer in AGENTS.md.
The checker reports a handler's msg cast to, or aliased as, EmbedIQ_Msg_t in fbs/ and examples/. The Service FB
template had the same envelope read, which turned its log length into two text bytes. It now copies at most one payload of
text up to the first NUL. The template is built as a library in every build and has a unit test. The thermostat
controller emitted LIFECYCLE and FAULT events with source 0, so its state changes appeared in the trace as fb_timer's. It
now reports each state entry as an APP event from its own endpoint, with the reading in tenths. The gateway and
thermostat handlers check msg for NULL before reading it.

This edits a comment in a core header (embediq_subfn.h); the declarations do not change.

Evidence

Checker red on the unchanged tree (16 sites), green after; a test for the per-rule allowance running in CI; all four examples
build and run with readable APP code= val= trace lines; the trace tool names the new event; full suite under ThreadSanitizer
0 findings. The env_monitor end-to-end script passes, including the cloud-command step.

The checker is red on the template before the fix (examples/service_fb_template/fb_logger.c:67: [R-sub-34]) and green
after; its fixture tests (8) cover the cast and alias forms, the path scope, an outgoing-message helper and (void)msg. The
thermostat observable test now drives the production controller. On the unchanged controller it finds the forged events
attributed to fb_timer and crashes on a NULL delivery; it passes after. The template test finds the wrong log length on the
unchanged template and passes after. A 45 s thermostat capture shows APP events from the controller and no gaps.

Limits stated

An application event carries one 8-bit code and one 16-bit value; multi-value readings are several events. Values are
fixed-point (tenths or hundredths, stated per code) and saturate at the field width. The checker catches envelope misuse
only through the handler parameter name msg; misuse under any other name is caught in review, not by the checker.

🤖 Generated with Claude Code

… printing; host programs may print by rule

Sub-functions receive payload bytes only. fb_north_bridge, fb_policy_engine
and fb_env_sim read them as a message envelope, so the north bridge never
sent or buffered a reading, the policy engine read the wrong bytes, and a
cloud command was never applied. Each now reads its payload directly; the
north bridge has one sub-function per message type.
@ritzylab-dev

Copy link
Copy Markdown
Owner Author

Reviewed PR #188 at be077fa, against base 2ce5941. No merge-blocking findings in this PR.

Reviewed the affected event API/formatting/decoder, example handlers and their publishers/dispatch contract, checker rule allowances/tests, and changed documentation. The gateway split by message type is consistent with payload-only dispatch. The MQTT publisher zeroes the complete inline payload, so the command handler’s bounded copy is valid for this path. Exact-path, per-rule main-program exceptions do not exempt sibling FBs or other forbidden rules.

Independent verification:

  • Isolated normal build and ctest: 32/32 passed.
  • Checker allowance tests: 5/5 passed; full check_fb_calls scan: 31 files, 0 violations.
  • CLI script: 28 assertions passed.
  • Direct payload probes: north bridge send/buffer/flush/alert values all correct; env command alert:25.0 emits CMD/THRESHOLD_SET and sets threshold to 25.0.
  • Exact-head CI run 41863401891: Linux 33/33, TSan 33/33, 0 report files / 0 findings / 0 runtime aborts.
  • Independently reproduced the same three boundary-checker test failures on the base commit. They are pre-existing, not introduced here.

Carry the disclosed adjacent work explicitly: logger template still treats payload bytes as an envelope and needs its own payload-contract correction/test; FUNCTION compile/runtime level wording belongs in the F7 truth audit. Add durable behavior assertions for the repaired example handlers with the payload-contract follow-up (the existing gateway integration test only checks successful process exit). None of these changes the scoped approval above or requires another revision of #188.

The newly supplied private P2B prompt is a separate review input; filesystem privacy blocked reading it, even with elevated access, so this comment does not claim that prompt has been reviewed. No source edits or merge performed.

…ller's state events carry its own endpoint; the logger template reads its payload (failing)
…late, checker; example controller reports its own events
@ritzylab-dev

Copy link
Copy Markdown
Owner Author

Final architectural/code recheck at 802124a: no blocking findings; ready to merge.

The agreed payload-contract corrections are implemented. The header documents existing dispatch behavior without changing signatures/layout/ABI; direct test delivery remains typed payload storage or NULL rather than an invented 64-byte minimum. Borrowed lifetime and alignment-safe memcpy are explicit. The checker matches narrow envelope-conversion forms in the intended paths and preserves legitimate outgoing-envelope pointer access. Logger boundaries are implemented and tested through the real engine/backend. Thermostat state events now use the controller’s own endpoint and APP type; the production-controller test uses a post-boot baseline and drives all three transitions plus NULL delivery. The static logger library is an appropriate adjustment to make the template buildable and behavior-testable.

Independent verification: full local ctest 33/33 passed; production controller 13/13, logger 12/12; checker tests 8/8, scan 31 files / 0 violations; standalone header compiles with C11 -Wall -Wextra -Werror; CLI 28 assertions pass. Exact-head CI 41962004239: normal Linux 34/34, TSan 34/34, 0 report files / 0 findings / 0 runtime aborts.

Architectural review of the core-header comment change is complete: it matches the existing payload-only dispatch and the host helper’s actual behavior. No further revision requested for #188. Known boundary-checker baseline failures and the missing WDG_CHECKIN stdout tag remain explicitly tracked follow-ups, not regressions introduced by this change. No source edits or merge performed.

@ritzylab-dev
ritzylab-dev merged commit 059203e into dev Nov 5, 2026
2 checks passed
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