Repository navigation
Add JSON output to recall search - #379
Conversation
Koukyosyumei
left a comment
There was a problem hiding this comment.
Approving. This is a clean, well-scoped addition: the JSON path is additive, the human output is untouched, and the field set is an exact match for recall objects --json, which is what makes the two feeds interchangeable for a headless consumer.
What I verified locally (worktree at dfce771, merged trial against main)
cargo test --test objects_e2e search_: 8 passed, including the newsearch_json_emits_typed_hits_and_an_empty_array.cargo clippy --all-targets --all-features -- -D warnings: clean.python3 scripts/gen_manual.py: regeneratesdocs/manual/index.htmlbyte-identically, so the committed HTML is genuinely fresh and themanuals fresh (man + html)gate will pass../scripts/gen_man.sh:man/man1/h5i.1unchanged, as expected.recallis a[REST]passthrough in the clap tree, so verb-level flags never reach the man page. No man regen was needed here.- Trial merge with current
main: clean.
Design notes
- Field parity with
ObjJsonis exact (14 fields, same names, sameskip_serializing_if), and.take(limit)matches the human path, so--limitbehaves identically in both modes. Good. - Emitting the full matched finding set per capture (rather than the human path's
PER_CAPTURE = 8cap) is the right call for a machine feed: a consumer that wants every hit should not have to fall back torecall object <id>.
Non-blocking suggestions
-
Drift risk in the duplicated struct.
SearchJsonrestates everyObjJsonfield. The next field added torecall objects --jsonwill silently not appear inrecall search --json, and nothing in the test suite would catch it. Consider one shared struct with an optional findings slot:#[serde(skip_serializing_if = "Option::is_none")] findings: Option<Vec<&'a h5i_core::structured::Finding>>,
plus a small
fn row(m: &Manifest, store: &LocalStore, findings: Option<...>) -> ObjJsonused by both arms. That also removes the third copy of theserde_json::to_value(status)round-trip, which already exists as the privateobjects::enum_strinh5i-core; making thatpubwould let both call sites share it. -
Silent truncation. When
hits.len() > limitthe human path prints— showing {limit}, but the JSON array just ends, so a consumer cannot distinguish 20 results from 20-plus. This matchesrecall objects --jsonexactly, so I would not change it in this PR; worth considering atruncatedmarker for both feeds later if CI graders start paging.
Nothing here blocks the merge. Thanks for including the zero-match [] case and the MANUAL.md capability-table row, both of which are easy to forget.
Adds
--jsontoh5i recall search, returning the same capture metadata asrecall objects --jsonplus only the findings matched by the query and filters. Empty searches return[]; the existing human output is unchanged.Adds integration coverage for typed metadata, finding fields, and zero-match output, and documents the new flag.
Closes #336
Testing
cargo test --locked --test objects_e2e search_json_emits_typed_hits_and_an_empty_array -- --exact --nocapturecargo test --locked --test objects_e2e search_ -- --nocapturecargo test --locked -p h5i-core objects::tests::search -- --nocapturecargo clippy --all-targets --all-features -- -D warningscargo build --verbose --all-targetscargo check --locked --target x86_64-pc-windows-msvccargo test --verbose(217 passed; the same seven WSL process-tier integration failures reproduce on the exact base)