read → (i32 | eof | closed), write → (i32 | closed), close → (void | closed). `type eof = void` and `type closed = void` are exported as named-void variants — distinct nominal tags despite identical (zero-byte) payloads. No existing callers exercised the eof/closed sentinels (the smoke test mimics the stream pattern with its own local types), so the graduation is purely API shape — no callsite churn.