Iter 6. Connects the typed payload parser (iter 5) to the framed
wire format (iter 4): the CRC32 now covers the section-prefixed
payload bytes per ADR-119 §2.2 ("CRC32 covers all section bytes
including length prefixes").
Added:
- BfldFrame::from_payload(header, &BfldPayload) -> Self
Auto-syncs header.flags HAS_CSI_DELTA bit from payload.csi_delta.is_some(),
serializes payload via to_bytes(), feeds BfldFrame::new() which computes
payload_len + payload_crc32 over the section-prefixed bytes.
- BfldFrame::parse_payload(&self) -> Result<BfldPayload, BfldError>
Reads HAS_CSI_DELTA bit from header.flags and dispatches to
BfldPayload::from_bytes(&self.payload, expect_csi_delta).
tests/frame_payload_integration.rs (7 named tests, all green):
from_payload_then_parse_payload_is_identity
from_payload_autosets_has_csi_delta_flag
from_payload_clears_has_csi_delta_flag_when_csi_absent
(verifies the flag is cleared when csi_delta is None even if caller
pre-set the bit; other flag bits like PRIVACY_MODE are preserved)
frame_crc_covers_section_prefixed_bytes
(mutating a byte inside section body trips CRC, not magic/length)
frame_crc_covers_section_length_prefixes
(mutating a section length-prefix byte trips CRC before parser ever runs)
empty_typed_payload_roundtrips
end_to_end_wire_roundtrip_via_bytes
(BfldPayload -> from_payload -> to_bytes -> from_bytes -> parse_payload
is the identity function modulo flag auto-set)
ACs progressed:
- AC5 ↑ — full payload round-trip through the framed bytes (closes
the round-trip leg from BfldPayload through wire and back).
- AC6 ↑ — same input produces same bytes through both layers.
- AC4 ↑ — CRC mismatch on tampered section bodies and tampered section
length prefixes both surface as BfldError::Crc, not as silent acceptance
or as a deeper parser error.
Test config:
- cargo test --no-default-features → 17 passed (integration tests cfg-out)
- cargo test → 39 passed (3 + 6 + 7 + 8 + 8 + 7)
Out of scope (next iter target):
- PrivacyGate::demote(frame, target_class) — ADR-120 §2.4 class transition
transformer with subtle::Zeroize on dropped fields.
- IdentityEmbedding newtype with no Serialize impl (ADR-120 §2.5 / I2).
Co-Authored-By: claude-flow <ruv@ruv.net>
Iter 2 of the BFLD rollout. Adds the canonical little-endian wire form for
BfldFrameHeader with safe (no unsafe) encoders/decoders. Covers ADR-119 AC5
(round-trip preservation), AC6 (deterministic serialization), and partial
AC1 (constant wire size) / AC4 (rejects bad magic + bad version).
Added:
- BfldFrameHeader::empty() — convenience constructor with magic/version set
- BfldFrameHeader::to_le_bytes() -> [u8; 86]
- BfldFrameHeader::from_le_bytes(&[u8; 86]) -> Result<Self, BfldError>
- Field-level doc strings on every header field (clears all 21 missing-docs
warnings the iter 1 commit logged)
- tests/header_roundtrip.rs — 6 named tests:
header_roundtrip_preserves_all_fields
header_serialization_is_deterministic
header_magic_is_at_offset_zero_little_endian (LE byte order proof)
parsing_rejects_invalid_magic
parsing_rejects_unsupported_version
wire_size_is_constant
Implementation notes:
- Used #[derive(Default)] on BfldFrameHeader so empty() can build cleanly.
- to_le_bytes copies packed fields into locals first to dodge unaligned-
borrow lints; from_le_bytes uses try_into() on byte slices.
- All field reads/writes are #[forbid(unsafe_code)] compliant.
Out of scope (next iter targets):
- BfldFrame (header + payload sections + section-length prefixes + CRC32
computation over payload bytes only) — needs the `crc` crate dependency.
- PrivacyGate::demote(...) skeleton (ADR-120 §2.4).
- SinkMarker traits (LocalSink / NetworkSink / MatterSink) — ADR-120 §2.2.
cargo test -p wifi-densepose-bfld --no-default-features → 9 passed, 0 failed
Co-Authored-By: claude-flow <ruv@ruv.net>
Land P1 of the BFLD rollout — the wire-format primitives:
- New workspace member: v2/crates/wifi-densepose-bfld
- PrivacyClass enum (Raw/Derived/Anonymous/Restricted) with allows_network()
and allows_matter() const helpers reflecting ADR-120 §2.2 and ADR-122 §2.4
- BfldFrameHeader (#[repr(C, packed)]) per ADR-119 §2.1
- BFLD_MAGIC = 0xBF1D_0001, BFLD_VERSION = 1
- BfldError variants for InvalidMagic / UnsupportedVersion / Crc / PrivacyViolation
- soul-signature cargo feature (gated, default OFF) per ADR-118 §1.4
- Compile-time size assertion via static_assertions::const_assert_eq!
- 3 acceptance tests in tests/frame_header_size.rs (all pass)
Bug fix:
- ADR-119 AC1 claimed BfldFrameHeader is 40 bytes. Actual packed layout sums
to 86 bytes. Updated AC1 and §2.1 prose to match. const_assert in frame.rs
pins the value structurally — a future field addition that breaks the size
fails to compile.
Out of scope for this iter (deferred to later P1 commits):
- Field-level missing-docs warnings (21) — addressed alongside accessor helpers
- Payload section parsing — needs the section-length prefix tests
- Round-trip serialize/parse — covered by a fixture-based test in the next iter
cargo test -p wifi-densepose-bfld --no-default-features → 3 passed, 0 failed
Co-Authored-By: claude-flow <ruv@ruv.net>