File access goes through confined capabilities, and Fs only attenuates

Decision

Fs, FsRead and FsWrite grant no file access themselves. Their only methods are attenuations: restrict_to, restrict_to_file, read_only and write_only. Every read and write goes through a confined capability:

Code that really needs the whole filesystem must write restrict_to("/"), and the authority report shows that root.

The first root, cut from Fs, FsRead or FsWrite, is a trusted String, so it is a structural position. Narrowing an existing directory capability further, with restrict_to or restrict_to_file, takes a Path that may come from untrusted text, because the result stays confined under the same root. Path carries no trust.

Why

Before this decision, a restricted and an unrestricted FsRead were the same type. The checker therefore could not see code reading a user-chosen path through an unrestricted capability, which is path traversal across everything the process can read (#48).

Making confined access the only kind of file access closes that hole with one rule. A signature such as fn build(docs: DirRead, out: DirWrite, readme: FileRead) states exactly where the function can read and write.

Considered options

Consequences