launchbound-tui and launchbound-report unwrap candidate.summary on the strength of a filter performed elsewhere: app.rs:257–317 ("filtered on Some", plus two bare unwrap()), report/build.rs:140 ("chosen is measured"). Each is true today; each is an invariant that lives in a different function from the code that relies on it, and a refactor of the filter breaks the unwrap silently.
Fix. Carry the guarantee in the type: a Measured newtype (or filter_map into a Vec<(Candidate, &Summary)>) at the filter site, so the consumer never holds an Option. Same treatment for build/cache.rs:48,62 and bench/run.rs:292,429 where a Result is the honest type.
Done when
launchbound-tuiandlaunchbound-reportunwrapcandidate.summaryon the strength of a filter performed elsewhere: app.rs:257–317 ("filtered on Some", plus two bareunwrap()), report/build.rs:140 ("chosen is measured"). Each is true today; each is an invariant that lives in a different function from the code that relies on it, and a refactor of the filter breaks the unwrap silently.Fix. Carry the guarantee in the type: a
Measurednewtype (orfilter_mapinto aVec<(Candidate, &Summary)>) at the filter site, so the consumer never holds anOption. Same treatment forbuild/cache.rs:48,62andbench/run.rs:292,429where aResultis the honest type.Done when
unwrap/expectonsummaryoutside test modules; the compiler enforces the invariant.