Typed wrappers for shell-state flow
A design study on using the type system to prevent a class of shell-state flow bugs — stale working directory, a field mutated in a child but never returned to the parent. It proposes three moves:
- give moved state typed wrappers (
Borrowed<T>,Returned<T>, plus the vocabulary Bound / Ambient for the other cases); - tighten environment-variable boundaries so process-owned keys are not cached;
- audit direct
std::env::current_dircall sites.
The guiding principle is restraint: use types only where the compiler can
prevent a realistic mistake. Bound is usually just Clone; Ambient is
absence; the wrappers earn their place only at the boundaries where a real bug
(PWD staleness, forgotten field return) would otherwise slip through.
A direction, not a committed implementation; the env-key question overlaps the open thread in env-overrides-scope-overlap.
Resolved without the wrappers. The two boundaries the study worried about were closed by other means, leaving the wrappers no realistic mistake to prevent:
- the env-key boundary moved to dynamic scoping in
env-is-dynamic-only —
env_overridesis the sole authority andPWD/OLDPWDlive only oncontext.cwd, so no process-owned key is cached where it could drift stale; - the direct
std::env::current_dircall sites were audited down to a few annotated, justified uses (core/src/path.rs, the uutils and pipeline-helper cwd snapshots), each carrying an explicit clippy exemption and a reason.
So Borrowed<T> / Returned<T> / Bound / Ambient were never built: by the
page’s own restraint principle — types only where the compiler can prevent a
realistic mistake — once those boundaries held, the wrappers did not earn their
place.