Close single-ownership follow-ups against systemd
Stacked on #26 (SOW-0097). Merge after it.
Closes the follow-ups from the single-ownership work, each checked against systemd and delivered in Go and Rust:
--list-bootsand-bmatch v262 on journals without_BOOT_IDDATA; callers opt into the old header fallback withBootListOptions, and listing errors are returned.- Verification keys follow the v262 grammar through one public SDK parser per language; the CLI copies are gone. Keys are judged per file, and a rejected key stops the run with v262's message.
- An unreadable DATA object or a payload without
=costs one field, not the entry, in both languages. - Go retention counts
*.journal~and deletes them first; Rust covers chain-named disposed files too. - Rust:
open_filesdeduplicates, single-value maps keep the first repeated value, a missing main entry array is detected at open, and boot ranges stop at the visible tail. - Non-UTF-8 source names convert the same way in both languages.
Validation against a systemd 262 oracle built with sealing: Go and Rust unit tests, byte identity, verify, directory, mixed directory, live, query, reader hardening and parser parity matrices. A differential of 29 verification keys on sealed and plain files shows no exit-code differences.
Known remaining difference: v262 prints a => Validated from ... summary after a sealed PASS; that needs a new SDK result type and is tracked by SOW-0177.
Summary by cubic
Closes the single-ownership follow-ups by aligning Go and Rust journal behavior with systemd v262 across boot listing, verification keys, damaged entries, retention, and source-name handling.
--list-bootsand-bnow match v262 on journals without_BOOT_IDDATA: no boots are listed by default, and callers opt into the old header fallback withBootListOptions; listing errors are returned.- Verification keys follow the v262 grammar through one public SDK parser per language, replacing the CLI copies; keys are judged per file and a rejected key stops the run with v262's message.
- An unreadable DATA object or a payload without
=costs one field, not the entry, in both languages. - Go retention counts
*.journal~files and deletes them before archived history; Rust covers chain-named disposed files too. - Rust
open_filesdeduplicates paths, single-value maps keep the first repeated value, a missing main entry array is detected at open, and boot ranges stop at the visible tail. - Non-UTF-8 source names convert the same way in both languages.
The one remaining difference is the => Validated from ... summary v262 prints after a sealed PASS; that needs a new SDK result type and is tracked in SOW-0177.