A checked vector is still a vector.
Eli Bendersky starts with a configuration function that reads a comma-separated environment variable into a Rust Vec<PathBuf>. The function rejects an empty vector. Its caller still receives a type that permits emptiness, so asking for the first item returns an Option and forces another branch.[1]
The check happened. The returned value did not retain what the check proved. Later code must trust control flow, a comment, or an unreachable! claim.
If success proves a fact, return a value that remembers the fact.
Parsing moves the boundary.
A non-empty collection stores a head and a possibly empty tail. There is no constructor for zero elements. Conversion from Vec can fail once. After it succeeds, first() returns an element instead of another question.[1]
Alexis King's original essay describes the same move as strengthening the input type. The caller stops carrying an impossible branch because the parser has changed the representation, not merely inspected it.[2]
Refine values in steps.
Bendersky points to rust-analyzer's absolute path type. A regular path can first become a UTF-8 path, then an absolute UTF-8 path. Each conversion establishes one fact. Code that receives the refined type does not need to ask those questions again.[1]
This is useful beyond Rust. Agent tools ingest paths, tool arguments, policy files, model output, and remote payloads. Convert each loose input into a smaller, named state before granting the next capability. Keep syntax, structural, semantic, and authority failures distinct.
Errors belong to the conversion.
Serde's documentation separates format errors such as unexpected input or trailing characters from errors raised while constructing a target value, such as a missing required field.[3] That distinction gives operators a repairable answer. The bytes may be malformed, the shape may be wrong, or the value may violate a rule.
Do not erase those failures into one "invalid config" message. Name the stage, the rejected field, and the expected form. Then return the refined value only after that stage passes.