CRT descriptor metadata prerequisite

This source checkpoint implements the descriptor foundation for the binary _fdopen plan in madbomber-fdopen-design.md; it does not register _fdopen.

_open now invokes one synchronous host operation that opens the real VFS file and retains the caller's CRT flags before returning the handle. The read-only fs_crt_descriptor_query(fd) returns these bits:

Bit Meaning
1 Live descriptor created by this CRT's _open
2 / 4 Currently granted read / write data access
8 / 16 / 32 Explicit binary / explicit text / unspecified translation
64 _O_APPEND

Zero means invalid, closed, foreign Win32 handle, existing fopen handle, or console descriptor. Explicit conflicting text/binary and invalid access modes fail before opening, allocating a handle, or truncating. Retaining flags is not a claim that every historical CRT open flag is implemented. Existing text/default byte-passthrough behavior is unchanged; future binary _fdopen must fail fast on these translation modes rather than treating them as binary.

The existing opaque disk handle is the identity: VFS allocation retains closed tombstones and never recycles a number, including after wraparound. A separate generation counter is therefore unnecessary. Query reads only the live handle record; it never loads lazy bytes, changes position or transfers ownership. Duplication copies the scalar CRT flags while retaining the existing shared position. Query derives rights from the duplicate's granted access, preventing access escalation through metadata. Close invalidates query through the same tombstone used by reads, writes and seeks. Process cleanup and stream close already go through this same VFS lifetime; no second descriptor table exists.

CRT append writes now append on every nonempty VFS write, including after seeking and through duplicates. Access and write-protection validation precede cursor changes. Zero-length writes retain the existing no-position-change behavior. The existing initial _open append seek is retained.

Both imports use the normal generated synchronous Worker broker. Cooperative instances share vfs through processSharedCtx; real Workers execute the same operations on the main host. There is no new region or per-instance mutable descriptor metadata.

Validation and outstanding work

Executed: node test/test-crt-descriptor-metadata.js, generated import signature freshness, JavaScript syntax, WAT fragment balance and diff whitespace checks. The small real-VFS test covers actual bytes, shared cursor, independent close, invalid/foreign descriptors, access denial and narrowed duplicate rights, per-write append, translation classification, query without data access, and same-process context sharing versus independent VFS isolation.

Executed after the coordinator's separate resource grant: node test/test-crt-descriptor-io.js. This compiles actual WAT handlers, asserts cdecl ESP preservation, exercises real read/write/seek/dup/close, and checks synchronous generic Worker-broker open and query against the same VFS. It does not spawn an OS Worker or claim concurrent close/adoption coverage.

Remaining: strict binary stream-mode parser; FILE allocation and descriptor ownership publication with close-race handling; errno policy; append adoption semantics; explicit treatment of preexisting fopen and standard descriptors; fdopen/fclose/freopen/OOM and concurrent lifecycle conformance; API registration and both generated API tables; subsequent fdopen build/regressions and original-game run. No game compatibility outcome is claimed here.

Compiled validation, 2026-10-18

The normal gated bash tools/build.sh and all four focused tests passed: test-crt-descriptor-metadata.js, test-crt-descriptor-io.js, test-duplicate-handle.js, and test-crt-stdio-file.js. The metadata test now includes a dedicated provider-backed file whose read methods throw, proving open/dup/query do not materialize its data. The broker test opens a real file through the broker, then reads and closes that descriptor through WAT.

The isolated candidate is 1,866,851 bytes, SHA-256 2f73127d24220248885e32c886538d236a68b04ae6ce7dec7b5fb8a012182166. The canonical recovery worktree artifact remained SHA-256 67aaa6df401d2039bd70dd4f71bd683b69524918dda5c7e93d735f19688e147f. Each supervised process exited zero with no remaining process group and no guard trigger. Minimum free disk across the successful build and tests was 2,272,362,496 bytes, above the 2 GiB + 64 MiB stop threshold. Each process started above the 2 GiB + 128 MiB admission threshold. The first build attempt stopped at missing committed toy-VM bundles in the sparse checkout; after materializing those exact files, the full build passed. Both attempts are saved.

Evidence and the JavaScript supervisor/recovery recipe remain under the isolated worktree's scratch/runs/20261018-crt-descriptor-validation/: per-command logs/JSON, artifacts.json (candidate and exact test hashes), and run.js. Reproduce with the repository build and the four tests above using the existing NODE_PATH=/home/user/wine-dashboard-deps-20261014/node_modules; no installation was needed. The reproducible generated build/combined.wat was hashed then removed to recover disk margin; rebuild regenerates it.