# Read-only cat state (K1286–K1290) `Cat` owns one native read-only file handle from open through explicit close. Open rejects an absent path before output. A bad handle read is an explicit error; the caller still owns the handle and can close it. A failed close returns the handle for retry. No heap allocation is required. Reads of 1–N bytes are data, even when shorter than requested. Only a zero read marks EOF. A writer failure preserves unread output bytes for retry. Operation budgets bound retries. The host contract covers 0, 1 and 513 byte files and negative handle/path cases. K1290 has development guest evidence from one experimental Image in six QEMU profiles; canonical product release acceptance remains open. ## Read-only directory listing (K1291–K1295) The input is a caller-owned directory path and an authority checked by the native directory service. The first supported paths are the root and one distinct child directory. The output is an ordered, bounded list of validated entries: each entry has a UTF-8 name, inode number, and file or directory kind. The service checks visibility for each entry before staging it; an entry the caller cannot access is omitted. The Rust boundary uses a borrowed `&str` path, an opaque caller authority, an owned handle, and a bounded `Entry { name, inode, kind }` value. Directory reads return `Entry`, `End`, or an explicit error. An end-of-directory result is distinct from an error. No path traversal or POSIX-compatible listing is implied. The lister starts idle. It requests a directory handle, reads no more than the format's maximum of 16 entries into private storage, validates every entry, and closes the handle before publishing the list. A successful close transfers no remaining ownership. An I/O or close error retains the handle for an explicit retry or cleanup. A bounded operation budget prevents an unending retry loop. ```text State + event Result + next state Idle + authorized open owned handle + Buffering Idle + absent/unauthorized open NotFound/Access + Idle Buffering + valid entry private entry + Buffering Buffering + inaccessible entry no entry staged + Buffering Buffering + end of directory no entry + ReadyToClose Buffering + malformed/read error Io + RetainedError ReadyToClose + successful close publish complete list + Idle ReadyToClose/RetainedError + bad close Io, same handle + RetainedError RetainedError + successful cleanup no output + Idle ``` An absent path returns NotFound. A directory outside the caller's authority returns Access before a handle or output is published. A stale handle returns BadFd without changing the current owner. Malformed names, duplicate names, invalid inode numbers, excess entries, and failed reads return Io and publish no partial list. A failed close reports Io and retains the handle. Only an authorized, fully validated directory can be listed. The positive case lists root and child separately and checks their different entries. The negative case denies an unauthorized child, verifies no output or handle leaked, then lists the authorized root with the same caller. K1292–K1294 have bounded Rust state and host tests. K1295 has six-profile development guest evidence from an experimental Image, including root output bytes, a denied child path, stale-handle rejection and owner cleanup. Canonical product release acceptance remains open. ## Process view and uptime (K1296–K1300) `ps` requests a read-only snapshot using an opaque caller authority. A `ProcessKey` contains a nonzero slot and generation; a recycled slot with a different generation is a different process. Each published row contains only the permitted key, optional parent key, public state (`Ready`, `Running`, `Waiting`, or `Exited`) and elapsed user-visible ticks. Kernel virtual or physical addresses, page table roots, stack bounds and private handles are never row fields. The snapshot has at most 16 rows and a generation/epoch chosen by the backend. Duplicate keys, invalid parents or an unknown state are errors. The order is stable for one snapshot; no live-update promise is made while displaying it. `uptime` obtains a monotonic tick count and a nonzero frequency from the same read-only service. The caller converts ticks to whole seconds and a fraction using checked integer arithmetic. Successive successful readings must never decrease for the same boot identity. A changed boot identity starts a new monotonic sequence. The elapsed value is an observation, not a wall-clock timestamp. The caller chooses `ListProcesses` or `Uptime`. `RequestAddress` is always rejected with `Access` before a snapshot handle is acquired. Absent/stale process keys return `NotFound`/`BadFd`; service interruption returns `Interrupted` with the owner retained for retry. Malformed metadata, arithmetic overflow, an exhausted operation budget and read/close I/O failures produce explicit errors. On failure, no partial rows or uptime are published. A failed close returns its handle for retry or explicit cleanup. ```text State + event Result + next state Idle + authorized snapshot open owned handle + Reading Idle + address request/denied authority Access, no owner + Idle Reading + valid permitted row private row + Reading Reading + end of snapshot private complete set + ReadyToClose Reading + stale/malformed/I/O error no public rows + RetainedError ReadyToClose + successful close publish rows + Idle ReadyToClose/RetainedError + bad close same owner + RetainedError RetainedError + successful cleanup no public rows + Idle Idle + valid uptime sample checked uptime + Idle Idle + decreasing same-boot sample Monotonicity error + Idle ``` The positive acceptance case has three distinct process generations and two nondecreasing uptime samples. The negative case requests a foreign address, checks `Access` and zero acquired owners, then confirms an authorized snapshot and uptime still work. K1296 defines these gates; implementation, fault injection and guest evidence are subsequent steps.