# P15-092 Stage0 Decision Status: `STOP`. B15 is `STOP-NO-SOURCE`; terminal static review status is `TERMINAL_REVIEWED_NO_SOURCE`. No production source, B15 case, or B15 fixture was created. Historical acceptance remains `NOT_TESTED`. P15-092 is the G11 zero-nlink candidate. The frozen BASE is `b22dae8dc634c68db4ea89dccade91350614c139`, the FreeBSD source HEAD is `106727738dcfb6c001b46f25363b91cece970085`, the erofs-utils source HEAD is `7db78788b000999e2de88decd2ba90654f26171c`, and the generator is `mkfs.erofs (erofs-utils) 1.8.6`. Linux EROFS identity is frozen by the three source hashes in `P15-092-input.json` and the Pre15 semantic audit hash ledger. The final gate script and input SHA256 values are `5943b85864da9095174ef51d1eed032ec6f0a1766c6465cb9660ea20cbd46b1e` and `0a6f6c76185644d3f5525a98429a310027556ef3cf7ebb43abb912f92e052bde`. ## Real Disk Oracle The gate creates the same deterministic source tree twice in forced compact form and twice in forced extended form. It uses fixed UUID, timestamp, worker count, xattr policy, and inline-data policy. Both complete host output trees are byte-identical. An independent parser reads the real superblock, checksum span, metadata block, root NID, directory entries, compact `i_nb.nlink`, extended `i_nlink`, and the compact `EROFS_I_NLINK_1_BIT` rule. It then materializes seven images: - compact and extended positive seeds; - namespace-reachable compact, extended, and directory inodes with nlink zero; - a root inode with nlink zero; - an unreachable inode with nlink zero, whose former name is redirected to a real hardlink NID and whose replacement link count is corrected to three. Every derived image has a recomputed valid EROFS CRC32C. `dump.erofs --path` resolves the actual directory edge and NID; no DUT helper or internal value injection is used. All seven images, including all three namespace-reachable zero-nlink images, pass `fsck.erofs -d0` with no error marker. The fixture-set SHA256 is `99897d4fd81da015bdaa66a5dfdbf3f42e9e830882c0d8c979e691fa9209ee7a`. Key deterministic host evidence SHA256 values are: - `host-result.json`: `59a27e9389e2771c921d689f6b76caeb858f0fd28487a933529153727aac12e8` - `disk-records.json`: `44bf0355dc5b34e93ec6868db9f9049de32500591b048a9016bf46aed9609485` - `boundary.json`: `985df1236c6dd2016d6cb244b71578d36bd4cd10aa273b60a92d5bb6d24d5b60` - `format-semantics.json`: `88efc1d7814103c044b36ff4dc3cac1dfa4da79f3d8955c682d1a60d9bfd9fcf` - `fixture-index.json`: `4d2b69bcc31709ecb96cfafb41f5db8ffcc97215c3290cfa476d0b6c7fc27886` - `source-anchors.json`: `ef9e6871d5fe1a3a6113f1172340269da4ea0c1692003aad0b0fee06ec4deb42` ## Linux and FreeBSD Semantics Linux EROFS calls `set_nlink()` with the compact or extended disk value and has no zero-nlink rejection in inode decode or super initialization. This is an inode/link-count behavior, not a FreeBSD vnode publication rule. Linux and FreeBSD both permit a live unlinked inode/vnode with link count zero; the FreeBSD VM code explicitly treats `va_nlink == 0` as an unlinked mapping case. The FreeBSD EROFS adapter has three distinct entry semantics: 1. `erofs_lookup()` owns a non-dot namespace edge and calls `erofs_vget()`. 2. `.vfs_vget = erofs_vget` is the raw NID entry used by VFS/root callers. 3. `erofs_fhtovp()` calls raw `VFS_VGET` and then maps `nlink == 0` to `ESTALE`. Therefore Linux's direct `set_nlink()` behavior does not authorize either a global FreeBSD rejection or a namespace-only rejection. The latter would be a new FreeBSD validator policy, and the disk/fsck corpus supplies no format-level rule requiring it. ## Publication Boundary B09 moved the vnode constructor to `src/erofs_vnops.c`, but the frozen B15 write set is only `src/namei.c` and `src/inode.c`. `erofs_vget()` inserts the constructing vnode in the hash, decodes the inode, marks it `VSTATE_CONSTRUCTED`, and only then returns to `erofs_lookup()`. A post-`erofs_vget()` check in `namei.c` is therefore too late to reject before vnode publication. `vput()` alone does not perform the required `vgone` cleanup. An unconditional `vgone()` cannot preserve an already cached vnode obtained through raw `VFS_VGET`, because `erofs_vget()` does not return a created-versus-hit indicator. Pre-reading through `erofs_read_inode()` would duplicate complete inode decode and metadata I/O on every cold namespace lookup, then decode the same inode again in `erofs_vget()`. The four failed GO requirements are consequently: - no format or cross-kernel rule requires reachable zero-nlink rejection; - rejection before vnode publication is unavailable within the exact B15 write set; - post-publication cleanup cannot preserve cached raw VGET semantics; - pre-reading would duplicate full inode decode for a low-value validator. Namespace and raw entrypoints are distinguishable, and the orphan needs no mount-wide scan, but those two facts do not outweigh the failed safety, compatibility, and cost requirements. P15-092 is therefore STOP rather than a partial or expanded-write-set implementation. ## Replay and Infrastructure The authoritative deterministic host command was run twice: ```sh timeout -k 10 240 tests/pre15/gates/P15-092.sh \ --base b22dae8dc634c68db4ea89dccade91350614c139 \ --output OWNED_OUTPUT --host-only ``` Both runs exit `22` with `STOP` and have byte-identical host output trees. One supplemental isolated runtime attempt used the standalone `/work/debug-qemu/local/vm/freebsd-build-runtime.qcow2`, not the protected base bp, with a fresh overlay, random port, exact baseline KLD, 180-second boot deadline, 60-second guest command deadlines, 900-second inner timeout, and 1200-second outer timeout. Run `20260815T083854Z-qemu-P15-092-gate-runtime-1219662-0` was `INFRA_BLOCKED`: guest SSH did not become ready before the boot deadline, so no runtime vnode result is claimed. The run used only PID `1219981` and port `49795`; it did not own PID `26318`, port `9222`, or the protected base bp. Cleanup is `PASS`: the owned QEMU PID stopped, port `49795` is free, the overlay and case temp were removed, and the standalone base SHA256 remained `ae09f47aef43cfd016049610e86bcf2073fdf70430961bcdb94662facac9f046`. The runtime manifest and cleanup SHA256 values are `2e9a4220dc86c5d8fa465e77e6d81e5e36c0f26338b70d71a84881af8fc02cb9` and `0a499d8fa3397f73998c6c3c3ae9dfc9070f61267a86361ba96d1e8bc64cb392`. Because the reproducible host gate already fails mandatory GO conditions, the runtime infrastructure block does not defer or weaken the STOP decision. It is reported separately and was not retried with another long-running VM. B15, TC021, TC025, TC182, K0, and B15 acceptance QEMU are `NOT_RUN` by the mandatory STOP-NO-SOURCE rule. The full feature suite was not run. ## Terminal Static Review The 2026-08-17 review rechecked the current `repo-pre-15`, Linux EROFS implementation, P15-092 plan, frozen write set, and post-STOP history. It found no format or cross-kernel requirement for namespace zero-nlink rejection, no new B15 consumer or test target, and no safe implementation entry within the frozen write set. The detailed evidence is `planning/pre15/evidence/20260817T-B15-terminal-review/VERDICT.md`. The terminal review does not convert the historical STOP or acceptance state: `STOP_NO_SOURCE` and `NOT_TESTED` remain the authoritative historical values.