I am not sure what willy-nilly means (programs need to be correct anyway), but the documentation clearly states that .items is meant to be directly accessed and I think it is good the way it is.
Also using ensureUnusedCapacity followed by passing unusedCapacitySlice to a function that needs a buffer and returns how many bytes it has written, followed by writing directly to list.items.len += written_bytes is a valid use case and because of ensureUnusedCapacity the later operations can’t fail, it also avoids creating an unnecessary intermediate buffer.
I think Zig is fine the way it is, if Zig wanted to (which it doesn’t seem to) become a more complex language, then I think a superset version of Zig could make sense that adds a kind of constraint/contract system, that lets you describe invariants with code to precisely track that certain properties aren’t invalidated (or even some optional extension like clr), but I don’t like adding some kind of half-solution that just restricts the programmers freedom from expressing the program they wanted to write.
There are already enough programming languages that restrict the programs you are allowed to write in them, towards those the language designer is most comfortable writing a compiler for.