This commit is contained in:
2026-08-18 09:20:44 +02:00
commit b826cd721a
522 changed files with 93730 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
# P15-005 Stage0 Decision
Status: `GO` for B06.
The authoritative baseline replay used commit
`edf098905a34de764185e72fc7e92d7b8f4e7285`. The gate extracts and compiles
the current FreeBSD `data.c` and `zmap.c` producer bodies instead of replaying
an arithmetic model. Fourteen frozen cases cover plain, inline, hole, chunk,
48-bit multidevice, compressed explicit extents, fragment, partial-reference,
post-EOF, bounds, overflow, short-read, and post-acquire error behavior. Every
field in `(m_la,m_pa,m_llen,m_plen,m_deviceid,m_flags,errno,acquire_count,
release_count)` matched the independently frozen record oracle.
The ownership oracle freezes 27 audited function bodies and 22 success,
validation-error, provider-error/short-read, transfer, and release paths across
plain data, compressed data/config, xattr, inode, superblock, and map consumers.
It also pins the corresponding Linux source hashes and `erofs_buf` acquire/put
semantic anchors. Candidate replay must satisfy the predeclared per-function
object/put/raw-buffer contract and execute the actual FreeBSD helper through
primary-image, metabox, error, overflow, idempotent-put, and null-callback paths.
The supplied prep remains correctly classified `BLOCKED`: its static scan uses
obsolete `erofs_mount`/`erofs_node` text anchors and its Python map model does
not execute DUT code. `P15-005.sh` and `P15-005-input.json` close those gaps on
the current BASE. Evidence is in
`planning/pre15/evidence/20260814T145546Z-G02-P15-005/`.
QEMU and the full feature suite were not run. G02 for P15-005 is a host/source
gate, and its candidate contract does not require either. This GO authorizes
B06 only; it does not authorize P15-006 or any B07 map-object change.
## B06 completion
B06 commit `1b1f904a674c21eed3ee29ca7df93c44429ac8d5` replayed the same
corpus and oracle with `object_mode=true`, `oracle_equal=true`, 14/14 tuples,
22/22 ownership paths, and five actual helper lifecycle paths. D, the B06 host
case, and both FreeBSD KLD configurations pass. Seven frozen FreeBSD raw I/O
and GEOM lifecycle functions are unchanged, and the pre-B07 map object hash is
unchanged. This completes the B06 dependency and unlocks B07a for its own
separate gated batch; it does not pre-approve a B07 implementation.
+60
View File
@@ -0,0 +1,60 @@
# P15-006 Stage0 Decision
Status: `GO`; B07a is complete.
The authoritative baseline replay used commit
`6673f51152a5195a8a8903aa801f820abce7936e`. This decision is independent of
the earlier P15-005 GO: P15-006 has its own corpus, model digest, source
extractors, byte encoding, and decision record.
The frozen corpus contains 80 map tuples and 13 device-resolution cases. The
map tuples comprise 50 plain/inline/chunk producer cases and 30 compressed
explicit-extent cases. They cover plain and inline boundaries, holes, raw
32-bit chunks, indexed 32-bit chunks, indexed 48-bit chunks, masked and
nonzero device IDs, all four explicit extent record sizes, fragments, partial
references, exact and post EOF, provider/metabox bounds, checked arithmetic
overflow, invalid formats and algorithms, and errors both before and after
metadata acquisition. The device cases separately exercise primary,
multidevice, flat-device, unified-address, missing-provider, range, and
overflow behavior without changing GEOM ownership.
Expected records are produced by an independent arithmetic and on-disk record
decoder whose frozen SHA256 is
`effcf0b6cc6a6e916eae89a14ad52d7b96273a453556647b6eabf2926fcb4abb`.
The gate separately extracts the real `data.c` and `zmap.c` producer bodies
from the frozen BASE, compiles them with `-Werror`, and compares every
`m_la`, `m_pa`, `m_llen`, `m_plen`, `m_deviceid`, `m_flags`,
`m_algorithmformat`, positive errno, acquire count, and release count. It
also packs those fields with fixed layout `<QQQQH2xIiiII`; the baseline tuple
bytes have SHA256
`8d3fec7ccbdfb7f7c851a494b6ecad02b8a019247bd9486188f8d37c169faedd`.
Two complete baseline replays produced byte-identical tuple, device, and
result files.
Protected hashes freeze the existing plain/chunk and compressed producers,
metadata acquire/put paths, physical I/O path, and device/GEOM mapping bodies.
The candidate replay additionally requires FULL and COMPACT dispatch to pass
all five map flag bits and all tuple fields through the new adapter. Every
observed acquisition is balanced: the baseline contains 41 paths at 0:0, 30
at 1:1, seven at 2:2, and two at 3:3. All successful non-EOF mappings have a
positive `m_llen`; Pre13 H07 remains closed.
This closes the specific Pre13 H01 oracle gaps for chunk, multidevice, bounds,
and overflow rather than reusing the old 26 plain/inline/hole tuples. The
supplied G02 prep remains a non-authoritative prototype and was not used as
the tuple source.
The B07a implementation is commit
`141b11f0d847a63a47b6c6143e4c2913a1147a0f`. Its authoritative host run
replayed all 80 tuples and 13 device cases against the frozen oracle. The
4,480-byte tuple streams are byte-identical with SHA256
`8d3fec7ccbdfb7f7c851a494b6ecad02b8a019247bd9486188f8d37c169faedd`;
FULL and COMPACT dispatch preserve every tuple field and all five map flag
bits. D and both K2 configurations pass, with no global or undefined symbol
delta from B06.
QEMU and the full feature suite were not run. The final plan requires host
tuple replay, D, and K2 for B07a; it does not require a B07a QEMU fixture.
B07b is now dependency-unblocked for a separate batch. B07c remains blocked
on B07b, and B08 remains blocked on B07c. This decision neither implements
nor pre-accepts any of those later batches.
+102
View File
@@ -0,0 +1,102 @@
# P15-019 Stage0 Decision
Status: `GO`. G03 authorizes B16 for P15-019 only. P15-046 remains the B01
test-only legacy xattr prefix fallback contract; it neither changes this
decision nor authorizes any exact-header or xattr behavior change.
The decision is bound to DUT BASE
`d645feb720c7022d2138d2a62eb72c022eb75351`, FreeBSD source HEAD
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils source HEAD
`7db78788b000999e2de88decd2ba90654f26171c`, and
`mkfs.erofs (erofs-utils) 1.8.6`.
## Authoritative Run
The gate ran from `/work/erofs-freebsd-pre/repo-pre-15` as:
```sh
umask 077
timeout -k 10 240 tests/pre15/gates/P15-019.sh \
--base d645feb720c7022d2138d2a62eb72c022eb75351 \
--output /work/erofs-freebsd-pre-evidence/pre15/\
20260815T093800Z-G03-P15-019-umask-fix/gate-output
```
It returned zero with `GO`. The authoritative hashes are:
- gate script: `afa20cbd28ca9dfc8064596a312248756ed7cde54398efb5ef713818cc04ea54`
- gate input: `291bf12838981ef650e16bbf7381eaa9b2921de957e97dec46e6a573750a19b8`
- result: `bb52e1a88cb09554a51432ec545ed98d5509a529832141ed0ce83b0c336be5bb`
- cases: `0c12cdce8b3ed37e85f349af0715a728d4acabbb758451fb65546dd9836066b5`
- fixture manifest/set: `5e99e5ad9112508991e78ae6e65928973d6b0da78285a059894bed06010cf373`
- semantics: `090e6b0cd5eaa197f17da12daf29f30bd8f337d3d4ae2f0f4f5819ad41e906f9`
- cleanup: `8e3b52610ee1492262494d00c48bf66ea04d313ab9ac1ef27565fa0e607b9a97`
An additional independent replay from `umask 077` produced the same result,
cases, fixture manifest, semantics, and cleanup hashes byte for byte. The gate
sets `umask 022` internally because erofs-utils records the packed fragment
inode's source mode; this makes the fixture set independent of its caller.
## Real EROFS Fixture Oracle
The gate creates 35 deterministic EROFS images and seven external chunk blobs
in owned output. Nothing is committed as an image, blob, binary, or KLD. Each
of the five required storage paths has these seven cases:
- normal short target;
- normal 1,024-byte `MAXPATHLEN` target;
- zero-byte target;
- embedded NUL at the first, middle, and last byte;
- 1,025-byte over-limit target.
Inline positives are native mkfs symlinks. Plain, chunk, compact compressed
ztailpacking, and whole-file fragment cases start as real mkfs regular-file
carriers because the host cannot create a symlink containing NUL and mkfs does
not select those layouts for symlinks. The transform changes only inode mode,
the root dirent type, and, for empty cases, inode size, then recomputes the real
EROFS checksum. Chunk data remains on a real `--blobdev`; fragment data remains
in the real packed inode. Changed-byte offsets are recorded for every case.
The independent Python parser reads the superblock, checksum span, inode,
dirent, layout, and target bytes directly. It resolves chunk indexes and the
external blob, decodes compact inline-pcluster raw LZ4 without a DUT helper,
and resolves the whole-fragment offset through the packed inode. It does not
compile, call, or inject values into any DUT internal function. `dump.erofs`
is only a layout/type cross-check. All legal targets also pass
`fsck.erofs --extract` and reproduce the exact source bytes.
The independent decision model returns positive FreeBSD `EINTEGRITY` (97) for
empty or embedded-NUL targets, positive `ENAMETOOLONG` (63) before target I/O
for size greater than `MAXPATHLEN`, and success for exact non-NUL bytes. No
trailing NUL is required. All 35 expected results match, so every layout has a
bounded positive and negative oracle as required by G03.
## Linux and FreeBSD Semantics
Linux `erofs_fill_symlink()` validates only flat-inline fast symlinks while
building `i_link`; it uses `kmemdup_nul()`/`strlen()` and returns negative
`-EFSCORRUPTED`. Non-inline Linux symlinks use `page_get_link`. That page/cache
shape is not a FreeBSD implementation contract.
FreeBSD enters through `VOP_READLINK` on a vnode and currently streams through
`erofs_readlink_target`, the common map/read path, GEOM or the compressed
backing path, and `uiomove`. It has no Linux `i_link` or page-get-link path and
uses positive errno. B16 must therefore validate the complete immutable target
before any `uiomove`, use the existing layout-specific map/read machinery, and
keep the scan bounded by `MAXPATHLEN=1024`.
The 1,024-byte case is a successful `readlink(2)` byte target. Pathname follow
may still return `ENAMETOOLONG` when that target plus the remaining pathname
exceeds FreeBSD's namei buffer; that VFS result is distinct from the on-disk
target validator. The 1,025-byte inode is rejected by B16 before target I/O.
## Scope and Cleanup
The gate did not modify `src/**`, build a KLD, start QEMU, or run a feature
suite. It observed but did not signal or otherwise alter protected PID 26318,
port 9222, or `/work/debug-qemu/local/vm-freebsd-build.qcow2.bp`; their recorded
identity was unchanged before and after the run. Owned temporary source and
extract directories were removed, with zero leftovers.
B16 may now modify only its planned source/test write set and must pass the
specified host TC166, D, zstdio0 build, and targeted TC166 QEMU acceptance.
+93
View File
@@ -0,0 +1,93 @@
# P15-021 Stage0 Decision
Status: `GO`. B19b source is authorized; B19a remains `STOP-NO-SOURCE`.
P15-021 is the xattr Bloom fast-negative candidate. The gate uses a real,
byte-reproducible EROFS image generated by `mkfs.erofs` 1.8.6, an independent
on-disk parser, a temporary file-local `erofs_xxh32` prototype, frozen Linux
format/use-site anchors, and five cold provider-metadata-read samples. It does
not link a prototype into the DUT KLD and does not modify `src/**`.
The required matrix is hit, proven miss, collision false positive, unknown
filter format, feature off, malformed shared-count metadata, malformed shared
ID metadata, positive FreeBSD errno, 64-worker replay, one million generated
names without a false negative, and owned cleanup. Unknown formats and feature
off must scan. A collision must scan. Structural corruption reached before or
during the scan must remain `EINTEGRITY` rather than becoming `ENOATTR`.
The gate command is:
```sh
timeout -k 10 240 tests/pre15/gates/P15-021.sh \
--base 666e52f710363df07f7c93919eb835d41092d011 \
--output OUTPUT
```
## Frozen Identity
The gate BASE is `666e52f710363df07f7c93919eb835d41092d011`.
`P15-021-input.json` freezes the three DUT source files, Linux `erofs_fs.h` and
`xattr.c`, FreeBSD 15 source HEAD
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils HEAD
`7db78788b000999e2de88decd2ba90654f26171c`, host tools, format constants,
thresholds, seven endian/seed vectors, one million generated names, 64 workers,
and the exact gate/source write sets. FreeBSD has no public xxh32 API; its only
copies are private Zstd/OpenZFS sources, so the authorized implementation is
file-local and namespaced as `erofs_xxh32`.
The generated prototype source SHA256 is
`3fe1a7a64ce4386d74f5f49455fe8bef2a2ee55a03eb72593a89d4dec70c1b4b`.
Its temporary host binary SHA256 is
`9910baed4d018a0257f38377bb48857a3205ee42d9f0ff279db71e63e5ba695b`;
the binary is evidence only, is not committed, and is never linked into the DUT
KLD.
## Fixture And Oracle
`mkfs.erofs` 1.8.6 generated the filter-bearing image twice from 64 peers and
one target with eight shared user xattrs. The two images were byte-identical;
the valid fixture SHA256 is
`b06b7c4c30adb3684d11505edf815dc0a395c03f6a95120b3150361008a182cb`.
The independent parser handles multi-block directories and separately decodes
inode xattr headers, inline entries, shared IDs, and shared entries. Legal
valid, unknown-reserved, and feature-off images pass `fsck.erofs`.
The seven-case matrix passes: present hit, proven miss, collision false
positive, unknown filter, feature off, malformed shared count, and out-of-range
shared ID. Miss alone takes the fast-negative. Hit and collision perform the
complete scan; unknown format and feature off perform the unchanged complete
scan. Corrupt header/shared metadata returns positive FreeBSD `EINTEGRITY=97`,
while valid absence returns positive `ENOATTR=87`.
The candidate implementation, independent Python xxh32, system libxxhash, and
the frozen Linux seed/endianness vectors agree. One million deterministic random
names across EROFS indexes 1/2/3/4/6 produce no candidate/oracle difference and
no false negative in 1,024 constructed valid filters. Sixty-four workers
complete 1,280 mixed lookups with identical bytes/errno.
## Benefit And Decision
Five cold samples of 200 real-fixture misses each are stable. Baseline metadata
read calls are `3400,3400,3400,3400,3400`; candidate calls are
`400,400,400,400,400`, an 88.235 percent reduction. Baseline cold unique
provider blocks are `400,400,400,400,400`; candidate blocks are
`200,200,200,200,200`, a 50 percent reduction. Both exceed the mandatory 25
percent threshold. The model counts the extra header/shared-ID reads on
positive and collision paths and therefore does not hide their overhead.
G03 is `GO` for P15-021. Only a proven negative may bypass the full scan; all
other outcomes retain the current FreeBSD extattr namespace, VOP transfer,
positive errno, metadata buffer ownership, and lock-free immutable lookup
behavior. Linux supplies the format/hash comparison, not FreeBSD vnode/cache or
locking semantics.
Attempt 1 stopped at the fixed-vector check because five hexadecimal hashes
were transcribed to incorrect decimal JSON values. Python and libxxhash agreed
on the hexadecimal values and bits; the input-only correction was replayed
under a new output directory. Attempts 2 and 3 then produced identical semantic
results and fixture hashes. Attempt 3 evidence is retained at
`/work/pre15-evidence/20260815T-P15-021-G03-attempt-3`; its `SHA256SUMS` digest
is `b81fe1b94048dbc3d17c62c95aba6a5de9e068e2a15639ca55ea60fe5a251e07`.
No QEMU or full feature suite was run for the Stage0 decision. Source remained
unchanged, owned temporary files/processes are zero, and protected PID 26318,
port 9222, and the base bp were untouched.
+87
View File
@@ -0,0 +1,87 @@
# P15-022 Stage0 Decision
Status: `GO`. B19a source is authorized.
P15-022 is the G03/G05 xattr-cache candidate. The old decision was not treated
as terminal because its multi-block path parser stopped before producing a
P15-022 result and G05 had zero samples. The repaired gate completed both
mandatory branches before source implementation.
## Frozen Identity
The replay base is `50a4e84d0da33592a81361e0294b7feb5bbd3ffa`.
`P15-022-input.json` freezes the current DUT/Linux source, exact-ABI FreeBSD
source `/work/dev-freebsd-releng` at
`106727738dcfb6c001b46f25363b91cece970085`, host tools, B17 assets, B19a
generator/oracle/model assets, a 1 MiB mount budget, a 64 KiB per-vnode body
limit, 64 workers, five samples per variant, and the unchanged 25 percent
provider-metadata-read threshold.
## Oracle Repair And G03
The B19a oracle now reads every logical directory block, including a short
final block, and validates name offsets, embedded NUL rules, strict in-block
ordering, strict adjacent-block ordering, stable entry order, duplicate
resolution, and missing-path classification. Its self-controls cover target
lookup after a block boundary, duplicate within/across blocks, duplicate
resolution, missing target, backwards boundary, and an invalid name range.
The real fixture retains 64 long-named peers and one target. It has 2 root
directory blocks, 68 entries, and resolves `target.bin` in block 1 after the
`peer-047`/`peer-048` boundary. The target contains both one inline xattr and
one shared xattr. Valid, corrupt shared-count, corrupt shared-ID, and corrupt
inline-name fixtures are independently checked with positive FreeBSD errno.
G03 completed twice on byte-reproducible images. The existing B17 oracle also
replayed twice with all 10 legal and 15 damaged images passing and frozen
fixture-set SHA256
`d821aeb36de37ae40b817b91f8169e585721c33a3a9e59098cdfbcbfff74e364`.
## G05 Result
The same image, host, operations, warmup, loops, and sample order were used for
both variants. Five raw samples per variant are retained; no failed sample was
filtered. Baseline provider metadata reads were
`1400,1400,1400,1400,1400`; candidate reads were
`800,800,800,800,800`. Median reduction is `42.857142857142854%` for both
instrumented calls and provider block reads, above the unchanged `25.0%` gate.
The focused cache model passes 64-worker one-owner publication, identical
waiter bytes and typed failure, failed initialization without a half-published
body, the 64 KiB entry limit, exact 1 MiB budget exhaustion fallback, invalidation,
inflight close, reclaim, and zero resident bytes after cleanup. The decision
is `GO`; source modification is now authorized only within the B19a write set.
## Evidence And Scope
Evidence is retained under
`planning/pre15/evidence/20260817T171814Z-B19a/`. `GATE-attempt1` preserves the
runner failure caused by the missing sample directory. `GATE-attempt2` is the
authoritative GO replay with raw fixtures, oracle reports, cache-model output,
sample JSON, aggregate TSV, commands, and cleanup manifest.
The authorized source/test write set is:
```text
repo-pre-15/src/erofs_vnops.c
repo-pre-15/src/inode.c
repo-pre-15/src/internal.h
repo-pre-15/src/xattr.c
repo-pre-15/tests/pre15/cases/B19a-xattr-cache.sh
repo-pre-15/tests/pre15/fixtures/B19a-*
```
No QEMU or production source was touched by this Stage0 gate. B36 and all
other execution units remain out of scope.
## B19a Acceptance Addendum
B19a subsequently implemented the authorized per-vnode xattr body/shared-ID
cache within the declared write set. The focused FreeBSD 15.0-RELEASE-p8
exact-ABI run passed first, concurrent, and repeated xattr reads; symmetric
`EINTEGRITY` results for all three damaged images; normal and forced unmount;
cache invalidation and reclaim; KLD unload; guest mount/md cleanup; target and
runner cleanup; and an empty dmesg delta. The runner retained the original
1200-second case deadline, focused command timeouts, 64 KiB body limit, 1 MiB
mount budget, and 25 percent G05 threshold. The final evidence is under
`planning/pre15/evidence/20260817T193130Z-B19a-final/`.
+43
View File
@@ -0,0 +1,43 @@
# P15-027 Stage0 Decision
Status: `STOP`. B36 is `STOP-NO-SOURCE`.
G07 is evaluated per architecture against frozen BASE
`4683579dabc57b0c9aaf5762e13ecc2a0ec3f8f9`. The mandatory audit set is
arm64, riscv64, and i386. i386 is the real FreeBSD 32-bit target: the
available FreeBSD source contains its machine headers and the pinned Clang
toolchain contains the x86 backend. Source/toolchain availability is not
native runtime evidence.
The inventory-first gate finds no declared same-architecture FreeBSD runtime
for arm64, riscv64, or i386. The host is Linux/x86_64. An emulator binary,
x86_64 guest, Linux execution, cross compilation, static layout output, or a
runtime from another candidate cannot satisfy this condition. Missing native
runtime is a per-architecture `STOP`, not `INFRA_BLOCKED`, and no architecture
can borrow another architecture's result.
Because cross-only results cannot change any current decision, dual
`WITH_ZSTDIO=0/1` KMOD builds and layout/unaligned/endian probes are
`NOT_RUN` for all three architectures. The gate still verifies the frozen
EROFS source tree, selected planning and probe hashes, FreeBSD source identity
and architecture headers, compiler identity and target backends, and exact
input-recorded Makefile relaxation. That patch is applied only to an owned
temporary Makefile copy. The production `src/Makefile` remains byte-identical
to BASE and retains the amd64-only error.
For a future rerun, each architecture has an independent native runner slot.
A declaration must pass a bounded preflight reporting matching FreeBSD
`uname -s`, architecture-specific `uname -m` and `uname -p`, and cleanup.
Only then does the gate create a frozen temporary source copy, apply the sole
recorded Makefile patch, build both KMOD configurations, record sizes and
`nm -u`, and compile the layout and unaligned little-endian probes. The same
runner must then load and unload both exact module hashes and record Plain,
LZ4, LZMA, and Zstd reads. It must also prove running-kernel `options ZSTDIO`
capability and exact disabled `EOPNOTSUPP`. Every operation carries argv,
deadline, exit, target marker, cleanup, stdout/stderr, and hashes. A candidate
is GO only when its own cross and native records both pass.
This decision does not authorize any B36 allowlist entry. No production
source, B36 case, B36 probe, QEMU run, K build, feature suite, or smoke suite
is created or run. Protected PID 26318, port 9222, and the shared base image
are outside the gate and are not addressed.
+51
View File
@@ -0,0 +1,51 @@
# P15-030 Stage0 Decision
Status: `STOP`. B37a is `STOP-NO-SOURCE`.
G08 is replayed against frozen BASE
`3e1d26a53eef30ecadc3407444d214feac861cb4`. P15-030 may proceed only if all
four conditions pass: an existing diagnostic or operational consumer, bounded
atomic counters, a FreeBSD 15 native `sysctl_ctx` lifecycle that closes every
required teardown path, and a stable privileged-read ABI that leaks no
unauthenticated metadata.
The consumer condition is evaluated first because no prototype can create its
own justification. The bounded inventory covers all 3,206 tracked paths under
`repo-pre-15` and `planning/pre15` at BASE, without reading
`planning/pre15/introduction.md` or treating this addendum as evidence. It
finds 54 broad sysctl/sysfs references: 31 planning or audit records, one
historical evidence record, 19 test-only paths, and three project reports or
documents. There are zero production or operations paths and zero qualifying
consumer declarations.
A qualifying future declaration must use schema
`pre15-p15-030-consumer-v1`, identify a versioned diagnostic or operational
consumer in production use, name its owner, workflow, deployment reference,
privileged-read access mode, and consumed signals, and bind a tracked non-test
implementation by path and SHA-256. The implementation must actually invoke
sysctl and reference each declared signal. A hypothetical future user, Linux
sysfs analogy, generic observability value, test script, or gate prototype is
rejected. If a declaration appears, this STOP-only run refuses false GO and
requires the FreeBSD 15 native lifecycle prototype before source authorization.
The first condition is `STOP`, so the bounded atomic-counter prototype,
FreeBSD 15 parse-failure/normal-unmount/forced-unmount/delayed-handler/
`sysctl_ctx_free`-failure lifecycle work, and permissions/ABI/leak probes are
all `NOT_RUN`. No host model is reported as native evidence and no prototype,
KLD, QEMU process, feature test, or smoke test is built or run.
P15-068 and B37b also close as `STOP` / `STOP-NO-SOURCE` because the plan
explicitly requires the P15-030 transport. This is capability dependency
closure, not an independent decision about UUID or volume-label formatting.
The identity oracle is `NOT_RUN`; no P15-068 gate addendum and no second sysctl
lifecycle are created.
The committed replay evidence is recorded under
`planning/pre15/evidence/20260816T041649Z-G08-P15-030/`. The gate owns one
temporary directory, uses a 60-second internal timeout plus the recorded outer
timeout, records argv, scope/source/addendum hashes, result, and cleanup, and
rejects an existing output directory.
No production source, B37a/B37b case, fixture, or empty commit is created.
Protected PID 26318, port 9222, and the immutable base image are outside the
gate and are not addressed or hashed.
+45
View File
@@ -0,0 +1,45 @@
# P15-031 Stage0 Decision
Status: `STOP`. B38 is `STOP-NO-SOURCE`.
G08 is replayed against frozen BASE
`0f696ad1e2c6628022d02ce52d07eb66704769dd`. P15-031 may proceed only if all
five conditions pass: an existing project diagnostic consumer that has
actually captured the complete predeclared mount/map/vget/xattr/decode/cache
schema through FreeBSD DTrace/SDT or a justified KTR path; no pointer,
credential, or unauthenticated metadata leakage; an owned-temp FreeBSD 15
prototype with exact fields/counts and closed failure/detach/unload lifecycle;
disabled `WITH_ZSTDIO=0/1` builds with no new undefined symbols; and a 10-run
hot-path median regression of at most 3% with retained interleaved controls.
The consumer condition is evaluated first because neither a gate prototype nor
a proposed B38 test can create its own project need. The bounded inventory
covers all 3,243 tracked paths under `repo-pre-15` and `planning/pre15` at
BASE, without reading `planning/pre15/introduction.md` or treating this
addendum as evidence. It finds 33 native-tracing references: 16 planning or
audit records, three historical evidence files, 10 test-only paths, and four
reports or documents. There are zero production/operations paths, zero
consumer manifests, and zero qualifying consumers.
A future declaration uses schema `pre15-p15-031-consumer-v1` under
`repo-pre-15/diagnostics/`. It binds a versioned production implementation and
actual FreeBSD 15 capture by path and SHA-256, identifies owner/workflow/
deployment, records privileged access and DTrace/SDT or justified KTR
transport, binds the complete event-schema hash, and records a positive count
for every event. The gate rejects a hypothetical maintainer, Linux
tracepoints, generic usefulness, a proposed test, its own prototype, or merely
installed `dtrace`. If an approved declaration appears, this STOP-only version
refuses false GO and requires the remaining native prototype, privacy, build,
and benchmark stages before source authorization.
The first condition is `STOP`, so privacy execution, prototype generation,
`WITH_ZSTDIO=0/1` builds, undefined-symbol comparison, the 10-run benchmark,
D/H/K0/K1, targeted QEMU TC178, full feature, and smoke are all `NOT_RUN`.
The gate's seven decision controls prove that GO is emitted only when all five
conditions are `PASS`; no benchmark samples or later-stage metrics are
fabricated.
No `src/erofs_trace.h`, trace callsite, `src/Makefile` change,
`tests/pre15/cases/B38-trace.sh`, source commit, or empty commit is created.
Protected PID 26318, port 9222, and the immutable base image are outside this
STOP path and are not addressed or hashed.
+106
View File
@@ -0,0 +1,106 @@
# P15-032 / G09 vnode-backed image gate
## Decision rule
This gate is source-preparatory only. It does not link its model into EROFS and
does not authorize B39 merely because a declared state sequence looks safe. It
pins and extracts the relevant FreeBSD 15 vnode, pager, mount, GEOM, md(4),
nullfs, unionfs, tarfs, and deadfs contracts, compiles an owned-temporary C
lifecycle model generated from `P15-032-input.json`, and rejects adversarial
false-GO mutations.
The runner exits with:
* `0`: gate GO;
* `10`: gate STOP;
* `20` or another nonzero value: runner failure;
* `124`: absolute gate timeout.
All phases have absolute deadlines. The generated C source and its output are
copied into the requested evidence directory; the temporary executable is
removed by the runner trap.
## Closeable local vnode contract
The pinned FreeBSD sources support a coherent local lifecycle:
1. Use an explicit `vnode:/absolute/path` tag; GEOM remains explicit or legacy
GEOM syntax. A mount and all `device.N` sources use one backend kind.
2. Resolve with `namei`, require `VREG`, retain vnode identity with
`vn_open_vnode(FREAD)`, retain the mounter credential with `crhold`, and use
that credential for every source `VOP_READ`.
3. Apply `VOP_SET_TEXT` before first I/O. The default write-count contract
rejects existing or later writers with `ETXTBSY`; retain a size snapshot and
convert a short source read into `EIO`. Rename or pathname replacement does
not change the held vnode identity.
4. Read synchronously into `UIO_SYSSPACE` under a source range lock and source
vnode lock. FreeBSD's old vnode-pager fallback drops the VM object write
lock before `VOP_READ`, so no user-buffer pager fault is introduced by this
read shape.
5. Register the source mount with `vfs_register_upper_from_vp` before first I/O.
On unmount, reject new I/O, drain delayed and in-flight completions, `vflush`,
unregister the upper mount, unset text, close the vnode, release the held
credential, and then release the final mount-private reference. A forced
dead source returns `ENXIO` rather than silently changing identity.
6. Keep GEOM open/read/close and vnode open/read/close as disjoint tagged-union
branches. This preserves the existing GEOM and multidevice behavior.
The generated model checks this order and independently removes each local
invariant to ensure that every mutation is rejected.
## Blocking FreeBSD contract
The required pre-I/O self and ancestor check is transitive across VFS and GEOM,
not only across pathname aliases:
```
regular source vnode
-> source filesystem
-> md(4) GEOM provider
-> md_s.s_vnode.vnode
-> another filesystem vnode
```
The final identity edge is not available through a generic, identity-preserving
FreeBSD API:
* `VOP_GETLOWVNODE` exposes vnode-stack aliases such as nullfs and unionfs, but
it does not traverse a filesystem's GEOM storage dependency.
* `vfs_register_upper_from_vp` pins the immediate source vnode mount and orders
its unmount, but it does not register hidden GEOM-to-vnode backing edges.
* `md(4)` stores the held backing vnode in the private `struct md_s` defined in
`md.c`. Its GEOM object exposes only `void *softc`; dump configuration exposes
a pathname, not a held vnode identity.
* Re-resolving that pathname fails the rename/replace invariant. Casting
`g_geom.softc` to a copied private `struct md_s` is an undocumented,
class-specific dependency and does not cover other filesystem-private or
GEOM-private file-backed providers.
Consequently a visible-only oracle can approve all vnode, credential, pager,
resize, and unmount checks while missing the hidden backing-vnode ancestor. The
gate includes that case as an adversarial false-GO control. There is no sound
place to return the required single cycle errno (`EDEADLK`) because the cycle
identity cannot first be discovered.
## Result
`P15-032` is **STOP** and B39 is **STOP-NO-SOURCE**. Recursive I/O and its lock
graph cannot be statically excluded for the requested regular-file source
surface using documented generic FreeBSD interfaces. A safe future GO needs a
new kernel dependency API that returns and pins transitive backing vnode
identities, or an explicitly narrower feature contract whose permitted source
filesystems have no hidden storage dependencies. Neither change is in B39's
authorized write set.
Run from the repository root:
```sh
repo-pre-15/tests/pre15/gates/P15-032.sh \
--base bd5a09054e5cf89efd4db82aadb051f20b06ebf7 \
--freebsd-src /work/build/freebsd-src \
--output /absolute/owned/output/path
```
No EROFS source, Makefile, feature documentation, B39 case, or B39 fixture is
modified by this STOP addendum. D, H, K, Q, TC006, TC179, TC184, smoke, and the
full feature suite are not run at the gate stage.
+85
View File
@@ -0,0 +1,85 @@
# P15-038 Stage0 Decision
Status: `GO`. B33 is authorized.
The authoritative frozen-BASE run is
`planning/pre15/evidence/20260816T021736Z-G05-P15-038/` against
`5d6755649a369498a9b257bb2d1d1e3496d5135e`. Its state model, hard-budget
accounting, real codec oracle, eviction check, and owned cleanup all pass.
The gate compares the current LZMA-only admission policy with a test-only,
codec-neutral single-entry decoded cache. Both variants execute the same 1,024
deterministic random 4 KiB logical reads against the same 256 KiB payload for
each of LZ4, LZMA, Deflate, and Zstd. Each variant has exactly five cold-cache
samples; no sample may be discarded. The helper uses the frozen host
liblz4/liblzma/zlib/libzstd libraries and performs real compression and full
decode work. It contains no synthetic sleep.
This is an independent host codec-cost oracle. It can prove avoided codec work
and byte correctness, but it is not guest vnode latency evidence and must not
be reported as such. Provider I/O, map lookup, VOP dispatch, and guest kernel
scheduling are outside its scope.
The state model preserves B32's exact key, one-owner, waiter, typed-failure,
retry, and no-cache fallback rules. It additionally freezes mount-cache then
global-budget lock order, reservation-before-decode accounting, codec-neutral
work/size admission, disabled policy, global exhaustion, ready eviction,
inflight reclaim refusal, successful reclaim, unmount drain, and key reuse.
Reserved plus resident decoded bytes are charged to the same hard budget.
G05 is GO only if the state model closes, all current/candidate hashes match,
eviction-before/after SHA-256 matches, every candidate sample stays within the
fixed budget, and at least two codecs improve median latency by 10 percent or
more. Any missing sample, correctness mismatch, lifecycle gap, or budget
overflow is STOP for P15-038 only.
## Result
All five current and five candidate samples are retained for each codec. The
median current/candidate latencies and improvements are:
| Codec | Current median | Candidate median | Improvement |
|---|---:|---:|---:|
| LZ4 | 44,988,337 ns | 6,583,335 ns | 85.367% |
| LZMA | 7,278,779 ns | 7,286,634 ns | -0.108% |
| Deflate | 186,791,959 ns | 6,102,297 ns | 96.733% |
| Zstd | 20,355,035 ns | 6,236,635 ns | 69.361% |
Three codecs exceed the required 10 percent threshold. LZMA is the expected
control because both current and candidate policies admit it; its negative
0.108 percent delta is retained and is not excluded or rewritten.
Every candidate sample charges exactly 262,144 resident bytes against the
262,144-byte mount budget. The state model reaches the 524,288-byte global
limit with two mounts, proves a third mount's synchronous no-cache fallback,
reclaims one reservation, retries successfully, and returns to zero bytes.
It also passes 16-thread success and typed-failure waves, ready eviction,
inflight reclaim refusal, key reuse, policy disable, low-work/oversize bypass,
and unmount drain. The real Deflate decode before and after eviction has
SHA-256 `5d3c21088380524a78c52b067d47a93117c5385464c5dfc83e8de598119511bb`.
No QEMU process was started by this pre-source gate. No guest vnode latency is
claimed. No production source, B32 correctness path, B32 QEMU runner, protected
PID 26318, port 9222, or shared base image was touched. B33 may now execute its
exact write set and acceptance matrix.
## B33 Execution
B33 source/test commit `bc56f830918b76029871b60cca2e53992de70a2e`
implements codec-neutral decoded-work/size admission with fixed hard mount and
global budgets, loader configuration/disable controls, four-codec accounting,
FreeBSD `vm_lowmem` reclaim, eviction, unmount release, and synchronous
no-cache fallback. It changes only `src/internal.h` and `src/zdata.c` in the
production tree and preserves the B32 key/inflight/failure contract.
D, authoritative H `20260816T025825Z-host-B33-cache-policy-1393732-0`, and
FreeBSD 15 cross-KLD builds with zstdio0 and zstdio1 pass. The final H-tested
seven-path source/test tree is byte-identical to the committed tree. Q
TC168-cache-inflight is `INFRA_BLOCKED`: guest SSH was not ready at the exact
absolute 300-second deadline, so no guest source, case target, KLD load, vnode
latency, or guest PASS is claimed. Owned PID 1389807, overlay, and port 33537
were cleaned; the protected process, port, and base metadata are unchanged.
The Q attempt predates the final replacement-order and policy-bypass-accounting
changes and did not reach the DUT. Full correspondence details and exact hashes
are in `planning/pre15/evidence/20260816T023315Z-B33/VERDICT.md`.
+44
View File
@@ -0,0 +1,44 @@
# P15-045 Stage0 Decision
Status: `STOP`. B35 is `STOP-NO-SOURCE`.
G07 is replayed against frozen BASE
`13974efc00c31d8c13c8dccb7c65a82adafcbff6`. Its first mandatory condition
is a concrete, versioned support/deployment manifest in existing project
evidence that identifies deployment targets and explicitly requires Zstd to
be enabled by default. General codec availability, prior Zstd test success,
Linux defaults, and maintainer preference are intentionally nonqualifying.
The gate inventories every tracked path in the frozen
`planning/pre15/evidence` tree (tree object
`3ecce7a124d153638853ab5d897126c769125309`, 2,560 paths), locates every text
record containing Zstd/Zstandard, and reviews records with deployment,
support, manifest, policy, default, or requirement signals. It accepts either
a structured JSON manifest or explicit text manifest headers, but requires a
manifest kind, version, nonempty deployment/support targets, and an
affirmative Zstd-default requirement together. The replay finds 596 Zstd text
records and 206 demand-signal candidates; no record meets that contract.
The missing deployment-demand prerequisite determines STOP before runtime or
build work. The disabled exact-`EOPNOTSUPP` runtime check, enabled real Zstd
EROFS read, FreeBSD kernel `ZSTDIO` symbol/capability check, and KLD size delta
measurement are therefore `NOT_RUN`; none is reported as PASS. In particular,
the gate does not claim or attempt to load a generic dependency KLD. A
false-GO guard requires every G07 condition to be PASS.
The frozen source is checked only to preserve the current policy boundary:
`src/Makefile` contains exactly one `WITH_ZSTDIO?= 0` default, the disabled
stub returns `EOPNOTSUPP`, and the documentation names kernel
`options ZSTDIO`. These are static observations, not substitutes for the
runtime conditions omitted after the prerequisite STOP.
The committed replay evidence is recorded under
`planning/pre15/evidence/20260816T033449Z-G07-P15-045/`. The gate owns one
temporary directory, uses a 90-second internal absolute timeout plus the
recorded outer timeout, records argv, source/candidate hashes, exit status,
and cleanup, and rejects an existing output directory.
No production source, B35 case, B35 fixture, QEMU process, full feature suite,
or smoke suite is run or changed. Protected PID 26318, port 9222, and the
shared base image are outside the gate. The supported policy remains opt-in
`WITH_ZSTDIO=1`, with default `WITH_ZSTDIO?=0`.
+74
View File
@@ -0,0 +1,74 @@
# P15-052 Stage0 Decision
Status: `STOP`. B20 is complete as `STOP-NO-SOURCE`; B21 was not started.
The authoritative G06 replay uses frozen BASE
`ca7bb4fe6b33e4a1bdf423801134b0ed6bda86dd`. It verifies the exact current
FreeBSD and Linux source hashes, the FreeBSD amd64 `PAGE_SHIFT=12` contract,
signed 64-bit `off_t`, and GEOM's `off_t mediasize` before evaluating every
listed branch.
## Exact Branch Result
All twelve proposed on-disk arithmetic branches have unique source sites, but
none has a target marker reachable from one validated on-disk field mutation.
The current source text returns positive `EOVERFLOW` at those defensive sites;
the proposed mapping would be positive `EINTEGRITY`. Linux has no matching
checked branches in these functions, so its relevant semantic mapping is
negative `-EFSCORRUPTED`, not a textual negative copy of the FreeBSD return.
The decisive counterexample to the supplied READY prototype is
`xattr.metadata.header_add`. The prototype directly mutates the local
`aligned_off` value. The real helper first rejects input above
`UINT64_MAX - 3`, then rounds to four bytes. The greatest surviving aligned
offset is therefore `UINT64_MAX - 3`; adding the two-byte header cannot
overflow. The named branch cannot be independently reached.
The other prototype vectors likewise inject values outside current provenance:
mounted image bytes are bounded by GEOM's signed `off_t mediasize`; inode size
is bounded by `OFF_MAX`; decoded physical blocks are at most 48 bits;
`blkszbits` is at most 12; prefix start and shared IDs are 32-bit. These bounds
prevent each proposed shift, add, alignment, and index overflow before the
listed target.
## Preserved Semantics
The replay separately freezes corruption, unsupported, provider I/O, EOF, and
short-read behavior. Disk/backing range contradictions remain positive
`EINTEGRITY`; exact zero-length EOF remains success; provider `EIO` and media
`ENXIO` remain exact; unsupported xattr layout remains positive
`EOPNOTSUPP`; allocation remains positive `ENOMEM` and outside B20. Linux
counterparts retain negative errno or `PTR_ERR` propagation.
The nominal `erofs_xattr_read_backing()` `off > INT64_MAX` positive
`EOVERFLOW` site is also not reachable for a mounted primary provider: the
preceding range check requires `off <= backing_size`, while mount validation
requires `backing_size <= INT64_MAX`. This site remains unchanged because a
STOP decision has no source diff.
## Atomic Decision
G06 requires every listed branch to be independently reachable. One missing
branch stops all of P15-052; this replay finds twelve missing target markers.
No `data.c` or `xattr.c` errno is changed, no B20 case/fixture is created, and
no candidate replay or QEMU run can cure a host-proven reachability failure.
The full feature suite was not run.
The authoritative command was:
```sh
timeout -k 10 240 tests/pre15/gates/P15-052.sh \
--base ca7bb4fe6b33e4a1bdf423801134b0ed6bda86dd \
--output OWNED_OUTPUT
```
It exited 1 because a valid gate `STOP` is not `GO`. Two fresh output
directories were byte-identical. The initial replay produced result SHA256
`37280545d8ef5a6b87c7b9d536939513a1bbac8e4e4b2389e84f5ca77e1aa522`,
branch-ledger SHA256
`8024a2cb6b43bd10fbcf446cf8cf44de37f1f9d6df25718c641cb9db4c257169`,
and preservation-ledger SHA256
`d17e05b8df43ea5173bed6e58d7431b37a7a9c4a143e07717b543efcb54ecc66`.
B21 is not authorized because the execution request requires B20 PASS before
B21. Wave16 is therefore not ready from this serial chain.
+13
View File
@@ -0,0 +1,13 @@
# P15-057 Stage0 Decision
Status: `GO`; B17 is complete.
The B17 fixture gate contains 25 reproducible EROFS images and independently
freezes all legal results and damaged positive FreeBSD errnos. The source
commit `433cf4ec66478b65b291ec5b21a0bf6d806bd14f` preserves the raw xattr filter
feature declaration, saves its reserved byte, and gates the current filter
format only at the ACL use site. Reserved values 0, 1, and 255 and feature
present/absent combinations pass host and minimal FreeBSD 15 QEMU replay.
Evidence is in `planning/pre15/evidence/20260814T203439Z-B17/`. This decision
does not authorize the separate cache, Bloom, or ordering batches.
+13
View File
@@ -0,0 +1,13 @@
# P15-058 Stage0 Decision
Status: `GO`; B17 is complete.
The B17 corpus separately covers inline names, shared names, and long-prefix
infixes containing embedded NUL, with independently frozen `EINTEGRITY` (97)
reject points. It also covers legal ACL empty-suffix names and short/long
name-index failures. Source commit
`433cf4ec66478b65b291ec5b21a0bf6d806bd14f` rejects only the length-delimited
embedded-NUL formats and retains the FreeBSD namespace and extattr ABI.
Evidence is in `planning/pre15/evidence/20260814T203439Z-B17/`. This decision
does not include xattr cache, Bloom, or call-order changes.
+89
View File
@@ -0,0 +1,89 @@
# P15-062 Stage0 Decision
Status: `STOP`. B26 is `STOP-NO-SOURCE`; no production source, B26 case, or
B26 fixture is authorized.
The decision is bound to DUT BASE
`205a90465edb64e83ba44aaacac9bedad4cbe905`, FreeBSD source HEAD
`106727738dcfb6c001b46f25363b91cece970085`, and exact upstream erofs-utils
commits for v1.4, v1.7, and v1.8.6. The authoritative gate evidence and final
script/input hashes are recorded below and in the G04 evidence commit.
The later B26 terminal review is recorded at
`planning/pre15/evidence/20260817T-B26-terminal-review/VERDICT.md`.
It retains `STOP_NO_SOURCE / NOT_TESTED` and adds secondary
`TERMINAL_REVIEWED_NO_SOURCE`. It found the historical zero-tail shape to be
reproducible, but did not establish that trailing zeros are format-mandated or
that current FreeBSD rejects them.
## Authoritative Run
The gate ran from `/work/erofs-freebsd-pre` as:
```sh
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-062.sh \
--base 205a90465edb64e83ba44aaacac9bedad4cbe905 \
--output planning/pre15/evidence/20260815T062257Z-G04-P15-062/gate-output
```
It returned the gate-defined STOP exit status 1. Evidence is rooted at
`planning/pre15/evidence/20260815T062257Z-G04-P15-062/`. The authoritative
script SHA-256 is
`6af503f1612eb42410f91a54fdc37481bae86a4419232c9de48c08bfa7ecee5d` and
the input SHA-256 is
`390202738ac006aba2514d27d3b0a19a0123a009601a26cac3b560a3dff388e5`.
The result SHA-256 is
`597466203edcaee6d163651a6d6a05e49dff24f39201234911f9753b29eebbe0`.
## Decision Rule
G04 permits P15-062 only if every normative and historical full LZ4 input uses
the same exact-consumption rule. The B26 review found that the old fsck
acceptance path uses `LZ4_decompress_safe_partial()` for legacy/no-0padding
images, so that acceptance does not prove full physical consumption or format
legality. The format sources contain no stored compressed-stream length or
general trailing-zero rule. The current FreeBSD decoder accepts an all-zero
remainder and rejects nonzero remainder bytes; no implementation defect was
demonstrated.
## Reproducible Corpus
The gate builds three upstream mkfs generations from exact commits in an owned
temporary directory. Each version twice generates the same fixed-time,
fixed-UUID, root-owned, xattr-free legacy LZ4 image from the same deterministic
1 MiB file. Matching `fsck.erofs --extract` accepts each image. The image,
source, build tree, and binaries remain temporary and are not committed.
The independent parser reconstructs the complete file from two physical
pclusters. The final extent has `m_plen=4096`, but its raw LZ4 stream reaches
9,670 decoded bytes after consuming 48 bytes; the remaining 4,048 bytes are
zero. This shape is byte-reproducible in v1.4, v1.7, and v1.8.6. The current
FreeBSD decoder accepts the whole input and liblz4 accepts the 48-byte exact
stream but rejects the block-sized input. The zero-tail shape is therefore a
historical tool-compatible candidate, not a proven format-legal fixture.
## Partial and Corruption Controls
A separate v1.8.6 `-Ededupe` image contains two real noncompact
`Z_EROFS_LI_PARTIAL_REF` records that share an LZ4 pcluster. The independent
parser, liblz4 partial API, and frozen DUT callback agree on the 4,096- and
5,594-byte prefixes. Corruption beginning after the 4,096-byte request remains
undetected by that partial read but causes the same fixture's full decode to
return positive `EINTEGRITY` (97), as required by G04. Truncation and nonzero
tail controls also return 97; all output guards remain unchanged.
Production `zdata.c` ownership anchors show that metadata/physical input is
released after every decoder return, failed decoded output is freed, and only
successful output is published. The decoder itself allocates and owns no
buffers. The gate's owned build/image directory is removed, and it does not
start QEMU or touch protected PID 26318, port 9222, or the shared base image.
## Consequence
P15-062 remains STOP for Pre15 because B26 has no authorized production source,
case, or fixture. `src/decompressor_lz4.c`,
`tests/pre15/cases/B26-lz4-input.sh`, and `tests/pre15/fixtures/B26-*` remain
unchanged or absent as applicable. B26 acceptance D, exact-ABI build, TC167
QEMU, and the full feature suite are not run because no implementation error
was demonstrated. The secondary B26 status is
`TERMINAL_REVIEWED_NO_SOURCE`.
+75
View File
@@ -0,0 +1,75 @@
# P15-076 Stage0 Decision
Status: `STOP`. B29 is `STOP-NO-SOURCE`.
The gate is bound to frozen DUT BASE
`3e9bc3f03ba9c39c38cc40f2f08eb6e769557f55` and FreeBSD source HEAD
`106727738dcfb6c001b46f25363b91cece970085`. Three host attempts are retained:
- `20260815T170841Z-G05-P15-076`: `RUNNER_FAIL`, FreeBSD headers shadowed
glibc headers during host compilation.
- `20260815T170931Z-G05-P15-076`: `RUNNER_FAIL`, the Deflate oracle compared
one selected extent with the complete source payload.
- `20260815T171051Z-G05-P15-076`: the runner returned 0, but final review
rejects its local `GO` because mandatory state-model conditions are not
closed.
## Last Attempt Command
```sh
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-076.sh \
--base 3e9bc3f03ba9c39c38cc40f2f08eb6e769557f55 \
--output planning/pre15/evidence/20260815T171051Z-G05-P15-076/gate-output
```
The command returned 0 in three seconds. The gate script SHA-256 is
`1d2cc18de150c8bdeb4fa8d284ab345f9ec4249c2ba1b50e1badbe7f942b42dc`,
the input SHA-256 is
`30497cf86785c367dcd4a3d6889ba6a6302f6f133d68e4af31d984a1031e0058`,
and the result SHA-256 is
`ac007afc4ad5a97bb1561888105c67612d3eea5427f77c54a858bede4c86e0a3`.
## Benefit Result
The last attempt regenerates the frozen B28 EROFS fixtures in owned temporary
storage and decodes the exact selected LZMA, Deflate, and Zstd extents. Input,
expected output, and output buffers are outside the tracked allocator region.
Baseline creates and destroys a context per decode; the prototype resets one
context across 64 exact decodes. Seven samples are retained per mode.
| Codec | Baseline events | Reused events | Reduction | Measured peak |
|---|---:|---:|---:|---:|
| LZMA | 128 | 2 | 98.4375% | 28,504 B |
| Deflate | 256 | 4 | 98.4375% | 39,928 B |
| Zstd | 128 | 2 | 98.4375% | 95,992 B |
All tracked baseline backend allocator events are context lifecycle events, so
the measured share is 100 percent and passes the 10 percent threshold. All
three event reductions pass the 25 percent threshold. Exact output and
balanced allocation/free counts pass. CPU remains diagnostic: Deflate is
1.30 percent faster, LZMA is 10.20 percent slower, and Zstd is 15.35 percent
faster by median per-decode time; the LZMA regression is retained.
## STOP Review
G05 requires both the benefit threshold and a complete pre-source state model.
The retained runner does not establish a hard memory limit: its 329,616-byte
mount and 2,636,928-byte global calculations use peaks from representative
streams. In particular, its Zstd prototype sets `ZSTD_d_windowLogMax` to 16,
while the frozen DUT accepts values through 20. The measured 95,992-byte Zstd
peak therefore is not a hard bound for the production-supported range. LZMA is
also sampled with a 65,536-byte dictionary while the DUT accepts up to 8 MiB.
The state model also does not execute a global-exhaustion transition. It sets
`global_owned` and `mount_owned` to the mount limit of two and selects fresh
allocation because the mount is full; the independent global limit of 16 is
never reached. Text describing global exhaustion cannot replace that missing
assertion. Therefore the hard-cap and global-exhaustion requirements are not
closed, and the runner-local `GO` cannot authorize source work.
No threshold, sample, or result is changed to force a decision. Per G05, one
failed mandatory condition makes P15-076 `STOP`; B29 is recorded
`STOP-NO-SOURCE`. No production `src/**`, B29 case, fixture, or helper was
changed. B29 H/K/Q acceptance, QEMU, and the full feature suite were not run.
The hard-timeout D check passed. Owned temporary cleanup passed; protected PID
26318, port 9222, and the shared base image were untouched.
+95
View File
@@ -0,0 +1,95 @@
# P15-081 Stage0 Decision
Status: `GO`. B11 is authorized; no production source was modified by this
decision.
The authoritative G11 replay uses frozen B25 BASE
`e2e3fb86b6fffcb01d6fd29c17dd95628ad070de`, FreeBSD source HEAD
`106727738dcfb6c001b46f25363b91cece970085`, and
`mkfs.erofs (erofs-utils) 1.8.6`. The gate script and input SHA256 values are
`6215a3005214ba8d25dacd63e039320a0c63308d2334b5faff99a3927cad7d2e`
and `a887fad56927545adb48462b770100d1e64b22b32554ed8ffad14c72b8febfc3`.
## Real Disk and Normal Entrypoint
The gate independently materializes a deterministic source tree containing
regular, directory, character-device, block-device, FIFO, socket, symlink,
and two hardlink names. It invokes mkfs twice with fixed UUID, time, ownership,
worker count, xattr policy, and inline-data policy. It also fixes and restores
the process umask and explicitly sets every source-node mode. Complete
replays under outer umask `022` and `077`, including both seed generations in
each replay, are byte-identical.
The gate parses the actual superblock, checksum range, root inode, inline root
directory, 12-byte dirents, NIDs, and compact inode modes without using DUT
helpers. Every derived image changes one real dirent byte and recomputes the
superblock CRC32C. `dump.erofs --ls --path=/` observes the mutated on-disk
`file_type`, while `dump.erofs --path=/NAME` reaches the same NID and reports
the inode kind from its mode. This gives 13 normal namespace resolutions from
real disk fields: eight known mismatches and five forward-compatibility cases.
All eight known mismatches are checksum-valid, fsck-clean images and yield
positive FreeBSD `EINTEGRITY` in the independent candidate oracle. Type zero,
nonzero dirent reserved bytes, and out-of-range type 8/255 remain accepted by
the DUT policy and candidate oracle. erofs-utils fsck separately rejects 8/255;
the evidence records that as `policy-reject` rather than falsely claiming
fsck-clean. P15-093 already freezes the FreeBSD behavior for these extension
values as `DT_UNKNOWN`, so fsck's stricter userspace policy does not override
the G11 compatibility boundary.
## Cache and Lock Boundary
`regular` and `regular-hard` are different namespace keys with the same real
NID. The first normal lookup can instantiate the vnode; the second name misses
that namecache key and reaches the existing `erofs_vget()` path, whose frozen
body checks `vfs_hash_get()` before inode decode. Mutating only the second
dirent to known directory type therefore provides the required cached-vnode
trigger without adding a readdir-time vget.
The generated candidate patch adds no lock, vget, hash, or recursive lookup
call. It reads immutable `vtype` after the existing child lookup, returns
positive `EINTEGRITY` for a known mismatch, drops the locked child with
`vput()`, and runs before `a_vpp` and namecache publication. Dotdot's existing
`vn_vget_ino()` path explicitly bypasses the validator because root `..` can
return the directory vnode itself; this preserves its parent-lock contract.
The parent/child lock order, readdir cookies, and VFS/VOP entrypoints are
unchanged. Readdir still contains no vnode lookup.
Linux supplies the format mapping: EROFS file type values match generic Linux
`FT_*`, and Linux readdir maps those values with `fs_ftype_to_dtype()`. The
candidate aligns that known-type mapping while retaining FreeBSD vnode types,
the FreeBSD 15 `__enum_uint8(vtype)` ABI type, positive errno, VFS locks, and
forward handling for unknown values.
## Replay Result
The authoritative command was:
```sh
timeout -k 10 240 tests/pre15/gates/P15-081.sh \
--base e2e3fb86b6fffcb01d6fd29c17dd95628ad070de \
--output OWNED_OUTPUT
```
It exits zero with `GO`: 14 generated images, eight known-match records
including the hardlink alias, eight known mismatches, five compatibility
cases, 13 normal entrypoint observations, one cached-vnode sequence, and 21
compiled prototype records. Two fresh output directories are byte-identical. The fixture-set
SHA256 is
`b562a7e42e139b16f3ce399d585aa7c373a66aa478a084bfed67b2b2aa9f2bd3`.
Key immutable evidence SHA256 values are:
- `result.json`: `4ec8e053c60ae75ae2fc4580a3d820a0452cf519f6b85376953135e18a7ec0ec`
- `oracle.json`: `932e558d3ead05572f38c89635bb10cae45393e42028031f81dfc7a56f2093f6`
- `lock-ledger.json`: `e8c2e6ba797fbcc83d832af6583d3f74f344750f6897111e7fe501130e577c13`
- `fixture-index.json`: `1a46b8ebfec16109c5d193001dc650a1b56000045e5d9e1e9b145fe7c5df9a16`
- `candidate.patch`: `427097da9304f5bedb770be8cab5f589706d316fb18a152ca16cb9d0663713fd`
- `prototype.c`: `1a295d18830c61a9708d465c3b1e415efb3ff8276100e4e32139bfa715195d8b`
- `normal-entry.tsv`: `b2841448068f70633ed0c02d901177a639cfed150f0e1c58977cc6c7b1e7313e`
- `SHA256SUMS`: `36b486617920b04ca87e88016e2fc0f519cda3a5f99dc675c9a89549615a02e3`
QEMU and the full feature suite were not run for this pre-source gate. The
gate uses host-created real EROFS images, independent binary parsing, normal
userspace namespace resolution, frozen DUT/FreeBSD control flow, and a
compiled prototype that is not linked into the DUT KLD.
+101
View File
@@ -0,0 +1,101 @@
# P15-083 Stage0 Decision
Status: `GO`. G04 authorizes B27 for all three non-LZ4 codecs. The source batch
must preserve the exact policies below and may not import the P15-062 LZ4 STOP
rule.
The gate is bound to DUT BASE
`68bbe94c44e35d53cec8ab55d007f40b01cf0502`, FreeBSD source HEAD
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils 1.8.6, liblzma
5.8.1, zlib 1.3.1, and libzstd 1.5.7.
## Authoritative Run
The gate ran from `/work/erofs-freebsd-pre` as:
```sh
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-083.sh \
--base 68bbe94c44e35d53cec8ab55d007f40b01cf0502 \
--output planning/pre15/evidence/20260815T142600Z-G04-P15-083/gate-output
```
It returned 0 and recorded `GO`. Evidence is rooted at
`planning/pre15/evidence/20260815T142600Z-G04-P15-083/`. The authoritative
script SHA-256 is
`6847541266b0668ad12442ffb54b67a772a29ed8ebe6fba0e1e25214db16b2c2`, the
input SHA-256 is
`b3c71b4ae03c6f9511246813952aab3178a1451433ece96f04562ec7cc6c1d1e`, and
the result SHA-256 is
`b9431b3819d64cdf940dff05ce7bc0e0bdf44c3ec647c90592052af5f7b3e544`.
## Decision Rule
P15-083 is GO only if LZMA, Deflate, and Zstd each have a reproducible real
EROFS fixture, an independent consumed-byte oracle, and a codec-specific policy
that distinguishes EROFS leading zero padding from unread nonzero bytes. Any
missing codec oracle, legal image rejected by the proposed full-stream policy,
or inability to distinguish trailing garbage makes the whole candidate STOP.
## Reproducible Corpus
erofs-utils 1.8.6 twice generates each fixed-time, fixed-UUID, root-owned,
xattr-free image from the same 151,552-byte source. Matching fsck extraction
reconstructs the complete source. The image hashes are:
| Codec | Image SHA-256 | Selected real extent | Leading zero padding | Stream |
|---|---|---:|---:|---:|
| LZMA | `c26cf15844fe45a21a746bacbad2ef551c683bb9b2538de7a7eced37d8eadff9` | 4,096 + 4,096 | 3,556 | 540 |
| Deflate | `39455150c3e999bb7ae6c36402c15a408a5679726b6d099e7d121e009ef43af6` | 28,672 + 4,096 | 1,479 | 2,617 |
| Zstd | `b905803f0e08500cc3c6cfe07a95fe027859165acae19ca8865856af256f32ca` | 4,096 + 4,096 | 1,092 | 3,004 |
The leading zero bytes are legal EROFS pcluster padding. They are removed by
the common dispatch before the codec callback, matching Linux
`z_erofs_fixup_insize()`. Every remaining legal stream reaches the format end,
consumes every byte, reproduces the selected logical extent, and leaves its
output guards intact.
## Per-Codec Policy
- Deflate: a full raw stream must reach `Z_STREAM_END` with no unread input.
The independent zlib decoder consumes 2,617 of 2,625 bytes after an 8-byte
nonzero tail and reproduces the output. fsck also accepts that mutation, as
does the Linux streaming loop when output is already full, but the bytes are
not EROFS leading padding and no mkfs fixture emits them. The audited FreeBSD
full policy rejects them with positive `EINTEGRITY` (97).
- LZMA: MicroLZMA stores no end marker and requires an exact compressed size.
The legal 540-byte stream consumes all bytes. Adding the same tail produces
liblzma status 9 after consuming 540 of 548 bytes; fsck rejects it and the
FreeBSD policy returns 97.
- Zstd: exactly one frame must finish with no unread input. The library finds
frame end after 3,004 of 3,012 bytes with the tail present; fsck rejects the
source-size mismatch and the FreeBSD policy returns 97. A concatenated or
skippable second frame is not EROFS pcluster padding.
This is deliberately codec-specific. It aligns Linux's non-LZ4 leading-padding
placement and stream completion semantics without copying the Linux wrappers'
implicit unread-byte acceptance into the FreeBSD provider path.
## Partial, Corruption, and Cleanup
The independent libraries decode real-stream prefixes that match the full
slice: Deflate produces 3,587 bytes after consuming 715, LZMA produces 4,096
after consuming 352, and Zstd produces 4,096 after consuming 1,457. Replacing
the final 64 stream bytes with zero begins strictly after each partial
consumption boundary. The same partial request still succeeds and matches;
full decode and fsck both fail for all three codecs, with the audited FreeBSD
policy mapping the full failure to 97. Removing the final compressed byte also
returns 97 for all three.
Every library path reports cleanup complete and unchanged guards. Frozen
`zdata.c` releases metadata or physical input after the callback, frees failed
decoded output, and publishes only successful output. The owned temporary tree
was removed. QEMU, protected PID 26318, port 9222, and the shared base image
were not touched. The full feature suite was not run.
## Consequence
B27 may now make these three existing policies explicit in the exact planned
write set and add TC176 host/QEMU coverage. It must preserve positive FreeBSD
errno, optional Zstd ABI, provider/GEOM ownership, input release, failed-output
free, and successful-output lifetime. The generated images, extracted files,
oracle source, and oracle binary remain temporary and are not committed.
+147
View File
@@ -0,0 +1,147 @@
# P15-086 Stage0 Decision
Status: `GO`. G04 and G05 authorize B28 partial subextent decoding for LZ4,
LZMA, and Deflate. Zstd is not authorized for partial decoding and must use the
exact full-decode fallback for ordinary strict subextent reads. Existing
partial-reference maps retain their bounded-prefix path. Shifted, interlaced,
unknown, and future backends also remain on full fallback unless a new gate
authorizes them.
The gate is bound to DUT BASE
`6bf5724619be70f805bbe7d1ba77dd70cdced69f`, FreeBSD source HEAD
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils generations v1.4,
v1.7, and v1.8.6 for LZ4, erofs-utils 1.8.6 for the stream codecs, liblz4
1.10.0, liblzma 5.8.1, zlib 1.3.1, and libzstd 1.5.7.
## Authoritative Run
The gate ran once from `/work/erofs-freebsd-pre` as:
```sh
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-086.sh \
--base 6bf5724619be70f805bbe7d1ba77dd70cdced69f \
--output planning/pre15/evidence/20260815T154915Z-G04-G05-P15-086/gate-output
```
It returned 0 and recorded G04=`GO`, G05=`GO`, and B28=`AUTHORIZED`.
Evidence is rooted at
`planning/pre15/evidence/20260815T154915Z-G04-G05-P15-086/`. The authoritative
script SHA-256 is
`591e407f20a6c8ab5d506329b3bd39ff7bd7f78b66ac86b9db2c45a498b31184`, the
input SHA-256 is
`62f7f505aef846fa85085039b2f47e252e11602e6ef1bf41f56841cdc9089a2a`, and
the result SHA-256 is
`33ef86b73447cd8c8099dc33901b9c4fff6c8ecedda3837d25cac9463a369d4f`.
## Decision Rule
Each codec is decided independently. A codec is partial-capable only when real,
twice-reproduced EROFS input decodes every requested range to the exact full
slice, reports a consumed-byte boundary before the end of the stream, leaves
guard pages unchanged, preserves positive FreeBSD errno, and reduces peak
temporary bytes by at least 20 percent without exceeding the fixed hard budget.
Failure of the benefit subgate selects exact full fallback for that codec; an
incorrect slice, unbounded memory, missing corruption boundary, or missing
oracle stops P15-086.
## Reproducible Corpus
All images are fixed-time, fixed-UUID, root-owned, and generated twice with
identical bytes. Matching fsck reconstructs every legal source.
| Codec | Generator | Image SHA-256 | Logical bytes | Physical bytes | Leading zero bytes | Stream bytes |
|---|---|---|---:|---:|---:|---:|
| LZ4 | v1.4 | `8f940673ed9f7e00efc5c0f06d41b2216748ea84256b740751aabff0d632de2b` | 1,038,906 | 4,096 | 0 | 4,096 |
| LZ4 | v1.7 | `93451e563f4eaf95b2690381074b5dfb3da0257691043c51619fd7d4c68dba7e` | 1,038,906 | 4,096 | 0 | 4,096 |
| LZ4 | v1.8.6 | `853649c78b159161421a6e833e0c516216382f3e8d135fc80aacd509ddb27b2c` | 1,038,906 | 4,096 | 0 | 4,096 |
| Deflate | 1.8.6 | `5f98ff39be30b1396be8164e54a8ae80b144d181d5295a640b2e7814406d7a2d` | 22,878 | 4,096 | 1 | 4,095 |
| LZMA | 1.8.6 | `887d4a9baf629533c8d512177a84ca256a20135157d29a201408534f63230889` | 151,552 | 4,096 | 3,556 | 540 |
| Zstd | 1.8.6 | `93f6beb46e77187ea8b0fc1ad3a5a1cb565d546d9ce40d51278f26d67187d5fa` | 151,552 | 4,096 | 1,092 | 3,004 |
The LZ4 corpus spans all three historical generators required by G04. Stream
codec consumption is reported by independent liblzma, zlib, and libzstd
decoders after the common EROFS leading-zero padding is removed. LZ4 is checked
by an independent raw parser and liblz4 partial/full output.
## Hard Budget and Benefit
The fixed input cap is 1 MiB, the decoded-output cap is 12 MiB, and the caller
cap is 1 MiB. Codec workspace caps are 0 for LZ4, 512 KiB for Deflate, 9 MiB
for LZMA, and 4 MiB for Zstd. These caps cover the frozen format maxima rather
than only the selected 4 KiB pclusters.
| Codec | Workspace full/partial | Hard cap | Baseline peak | Candidate peak | Reduction | CPU median partial/full | Decision |
|---|---:|---:|---:|---:|---:|---:|---|
| LZ4 v1.8.6 | 0 / 0 | 14,680,064 | 1,047,098 | 12,288 | 98.826% | 10,688 / 208,150 ns | `GO` |
| Deflate | 39,928 / 39,928 | 15,204,352 | 70,998 | 52,216 | 26.454% | 14,207 / 61,627 ns | `GO` |
| LZMA | 98,992 / 98,992 | 24,117,248 | 258,736 | 111,280 | 56.991% | 21,384 / 80,329 ns | `GO` |
| Zstd | 95,992 / 313,080 | 18,874,368 | 255,736 | 325,368 | -27.228% | 109,253 / 91,015 ns | `FULL_FALLBACK` |
All three LZ4 generations have the same 98.826 percent memory reduction; their
partial/full CPU ratios are 4.845, 4.632, and 5.135 percent. The gate collected
nine samples of 25 decodes per mode and stopped at that fixed sample count.
CPU timings are diagnostic because host scheduling produced visible outliers;
the authorization is based on deterministic peak temporary bytes. No noisy CPU
sample is used to rescue a codec that misses the 20 percent memory threshold.
## Ranges, Corruption, and Errno
Prefix, cross-page, middle, and tail requests all match the corresponding full
slice. The tail request reaches the extent end and therefore exercises full
fallback. Prefix consumption is 1,032 bytes for LZ4, 805 for Deflate, 352 for
LZMA, and 1,457 for Zstd. Corruption begins later at stream offsets 4,032,
4,031, 476, and 2,940 respectively. Every partial prefix remains byte-exact;
the same full read and every one-byte truncation return positive `EINTEGRITY`
(97). Real corrupted EROFS images fail matching fsck. All output guards and
codec cleanup checks pass.
Partial success is only evidence that the requested slice is correct. It is not
reported as verification of bytes after the consumed boundary or of the full
extent.
## State and Cleanup Model
B28 adds no persistent cache, owner, waiter, pool, or unmount-drain state. A
cache hit remains first. A gate-authorized strict subextent miss decodes into a
request-local bounded prefix and never publishes a partial cache entry. Full
requests, unsupported ordinary strict subextent codecs, shifted/interlaced
maps, and arithmetic fallback retain the existing exact full-decode/cache
policy. Existing partial-reference maps remain bounded-prefix and
cache-ineligible. Failure frees the local output after input release; success
publishes no shared partial state. Reclaim, eviction, unmount, and key reuse
therefore retain their existing ownership model.
The owned temporary tree was removed and the evidence SHA-256 manifest verifies
in full. No QEMU process was started. Protected PID 26318, port 9222, and the
shared base image were not touched. The full feature suite was not run.
## Consequence
B28 may implement bounded-prefix decode only for LZ4, LZMA, and Deflate in the
exact planned write set for ordinary strict subextent reads. Zstd and all
non-authorized backends must retain exact full fallback there without returning
an unsupported error; existing partial-reference behavior remains unchanged.
B28 acceptance owns D, the targeted TC176 host case, both KLD configurations,
and strict-timeout TC176 QEMU. It must preserve guards, consumed-byte semantics,
positive errno, cache eligibility, provider/GEOM ownership, and cleanup
ordering.
## B28 Execution Outcome
B28 source/test commit
`7a0d7e4a4047ac6d6130a3be5cb677cb94979fe7` has the exact 11-path actual
write set. LZ4, LZMA, and Deflate ordinary strict subextent reads decode a
bounded prefix; Zstd and non-authorized backends use exact full fallback.
Existing partial-reference maps remain bounded-prefix and cache-ineligible.
Final D, targeted host TC176 subset
`20260815T163642Z-host-B28-partial-1356298-0`, and targeted zstdio0/zstdio1 K2
`20260815T163515Z-host-B28-partial-1355895-0` pass. Earlier host and K2
`RUNNER_FAIL` records are retained with their corrected oracle/build findings.
The strict-timeout QEMU run
`20260815T163824Z-qemu-B28-partial-1356729-0` is `INFRA_BLOCKED` because guest
SSH did not become ready before the boot deadline; it did not reach the target
marker, so no guest TC176 runtime PASS is claimed. Owned cleanup passes,
protected PID 26318 and port 9222 were untouched, and the full feature suite was
not run. Complete evidence is under
`planning/pre15/evidence/20260815T161336Z-B28/`.
+95
View File
@@ -0,0 +1,95 @@
# P15-087 Stage0 Decision
Status: `STOP`. B12 is `STOP-NO-SOURCE`; no production source, B12 case, or
B12 fixture is authorized.
The final decision uses frozen DUT BASE
`c7d692acf9166f5c5e42335db2de64f0793ba8a2`, FreeBSD source HEAD
`106727738dcfb6c001b46f25363b91cece970085`, and
`mkfs.erofs (erofs-utils) 1.8.6`. The final gate script and input SHA256 values
are `349720b900ad2288153c9830f5f5ee84b8da707c06ffabcbd8e3e7a7e89f9e2a`
and `cb3aaa6c780c7b1efbd7c339f2b2da2ed8bf38d3ba32229dc17996807fd00787`.
## Workload and Independent Oracle
The gate deterministically creates 18,000 long-name regular files. Since
erofs-utils tailpacks the root directory even with `-E noinline_data`, the
generator moves the final 1,456-byte tail into one appended contiguous block,
changes only the root layout from flat-inline to flat-plain, increments the
superblock block count, and recomputes CRC32C. A second generation is
byte-identical and `fsck.erofs -d0` exits zero.
The independent parser does not call DUT code. It verifies a 3,880,368-byte
flat-plain directory at physical block 282, covering 948 contiguous 4 KiB
blocks and 18,002 entries. Its expected final cookie is 3,880,368 and its
record FNV64 is `427bb414efa99dc0`; the random offset is 1,937,408. The fixture
SHA256 is `3ecc5b706dd43b734c7e14a648a2bed2fb97a9f7963d4db703d15de81dc07a9d`.
The immutable `oracle.json` SHA256 is
`f247bbe5029301265342ff2098fcbd463a25e4752608826cbc1126d6620ef5d6`.
The generated prototype patch SHA256 is
`33b25131a611eec9c8731e88e4c258dfc92fe5897dd6781b6c95414a846dd2d1`.
Static extraction proves that it calls `breadn` only on the mapped backing
`devvp`, does not call `breadn` on the EROFS directory vnode, caps the window
at exactly 1 MiB, gates readahead on an offset-zero sequential readdir, and
adds no VM entrypoint, vnode lock, GEOM ownership operation, `cluster_read`,
or errno token. The `semantic-ledger.json` SHA256 is
`d26dbc37f4f34f65d07745a1b8069217d18545436d7f16f24e775e8c2db1a6b3`.
This closes the static design boundary but cannot replace runtime proof.
## Quantitative Decision
| Required G11 measurement | Required | Valid result | Decision |
|---|---:|---:|---|
| Cold sequential runs | 5 baseline + 5 prototype | 0 + 0 | FAIL: no median |
| Median latency improvement | at least 10% | not measurable | FAIL |
| Extra provider reads | at most 25% | not measurable | FAIL |
| Readahead window | at most 1 MiB | 1 MiB static cap | PASS |
| Random seek readahead | zero | 0 valid runtime samples | FAIL: not verified |
| Hash/cookie equality | exact independent oracle | 0 valid runtime samples | FAIL: not verified |
No run produced `runs.tsv`; therefore no latency, read-transfer, random-no-op,
or runtime hash/cookie value is claimed. It would be dishonest to infer GO
from the static prototype, from QEMU startup, or from build progress. Because
the workload could not be measured credibly and repeatably, G11's explicit
rule requires low-confidence STOP even though the 1 MiB static bound passes.
## Replay Ledger
The authoritative command shape was:
```sh
timeout -k 30 1200 tests/pre15/gates/P15-087.sh \
--base c7d692acf9166f5c5e42335db2de64f0793ba8a2 \
--output OWNED_OUTPUT
```
Existing evidence was retained long enough to hash and reconcile before
repository cleanup:
| Run ID | Result before any benchmark sample |
|---|---|
| `20260815T044720Z-G11-P15-087` | Superseded generator STOP: mkfs root remained flat-inline |
| `20260815T044924Z-G11-P15-087` | `INFRA_BLOCKED`: 12 boot-time providers exceeded SSH deadline |
| `20260815T045505Z-G11-P15-087` | `INFRA_BLOCKED`: FreeBSD did not enumerate PCI-hotplugged virtio-blk devices |
| `20260815T050003Z-G11-P15-087` | `INFRA_BLOCKED`: guest benchmark declaration error |
| `20260815T050520Z-G11-P15-087` | `INFRA_BLOCKED`: baseline KLD load did not reach workload |
| `20260815T051933Z-G11-P15-087` | `INFRA_BLOCKED`: phased baseline KLD load did not reach workload |
| `20260815T053543Z-G11-P15-087` | `INFRA_BLOCKED`: exact-basename baseline KLD load did not reach workload |
| `20260815T054540Z-G11-P15-087` | Aborted on instruction; owned process group terminated and audited |
Each completed QEMU ownership record reports that the owned port was free
after cleanup, protected PID 26318 retained the same identity, protected port
9222 was not used, and `/work/build/vm-freebsd-build.qcow2.bp` retained inode,
size, mtime, and ctime. The interrupted run used owned PID 1172175 and port
49845; both were absent after targeted process-group cleanup. Final process
audit found only protected QEMU PID 26318.
## Semantic and Batch Consequences
Runtime preservation of FreeBSD vnode, VM, locking, GEOM, errno, hash, and
cookie behavior was not established. Correctness may not depend on
readahead, so static plausibility is insufficient. P15-087 is STOP for Pre15,
B12 remains absent, and no host feature case, K0 build, TC183 QEMU acceptance,
or full feature suite is run. Rollback is the single gate decision commit;
there is no source commit to revert.
+142
View File
@@ -0,0 +1,142 @@
# 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.
+62
View File
@@ -0,0 +1,62 @@
# Pre15 Stage0 Execution Evidence
## Scope
B01 establishes the only Pre15 runner interface and the evidence contract used
by later gates, builds, directed tests, and smoke runs. It does not modify
`src/**`, run the full feature suite, or convert host parser results into KLD
runtime claims.
## Entrypoints
```sh
timeout -k 10 240 tests/pre15/run-host.sh CASE
timeout -k 30 1200 tests/pre15/run-build.sh zstdio0
timeout -k 30 1200 tests/pre15/run-build.sh zstdio1
timeout -k 30 1200 tests/pre15/run-qemu.sh CASE
timeout -k 30 1500 tests/pre15/run-smoke.sh final-four-codec
```
Cases are discovered as exact files under `tests/pre15/cases/`; no shared case
registry or historical result runner is consulted. `run-build.sh` reports a
Linux invocation as `INFRA_BLOCKED` because `build.sh` requires a native
FreeBSD host.
## Evidence
Set `PRE15_EVIDENCE_ROOT` to a new evidence parent. Every invocation creates a
unique run directory and never overwrites an earlier run. `manifest.json`
conforms to `tests/pre15/EVIDENCE-SCHEMA.json` and records exact argv, DUT and
source identities, worktree diff hash, fixture/module hashes, timestamps,
deadline, exit code, target marker, status, cleanup, and raw-output paths.
The only case statuses are `PASS`, `DUT_FAIL`, `RUNNER_FAIL`,
`INFRA_BLOCKED`, `STOP`, and `NOT_RUN`. A nonzero guest command without a target
marker is not a DUT failure. Cleanup failure always changes the run to
`RUNNER_FAIL`.
## Ownership
The runner records each owned process, path, forwarded port, SSH ControlMaster,
guest mount, md unit, loaded EROFS KLD, and base image before use. Cleanup runs
in reverse order and refuses to remove paths outside the current run directory.
QEMU always writes to a fresh overlay. The base image is read-only input for the
runner and its SHA256 must remain unchanged.
Mount, md, and KLD cleanup applies only to resources explicitly registered by
the current run. Kernel ZSTDIO is a kernel option, not an unloadable dependency.
## B01 Controls
- `B01-runner-selftest`: known-good, target-marked DUT mismatch, pre-target
command failure, SSH failure, QEMU early exit, timeout, owned PID cleanup, and
deliberate cleanup-boundary failure.
- `B01-g3-equivalence`: verifies the two archived script identities, compares
their source/artifact inventories with the stable helper, and repeats stable
generation.
- `TC162-xattr-legacy`: verifies checksum-valid legacy primary, explicit plain,
packed, and metabox prefix carriers plus exact single-field `EINTEGRITY`
negatives.
The authoritative B01 and initial gate verdicts are recorded under
`planning/pre15/evidence/` after execution from a committed B01 tree.
+101
View File
@@ -0,0 +1,101 @@
# Phase 0: B-ZSTD-001 Remediation
Status: `FIXED_STATICALLY`; runtime corruption-tail verification remains
`NOT_TESTED` in this remediation pass.
## Problem
Strict audit item B-ZSTD-001 / BUG-ZSTD-035 found that ordinary ZSTD extents
advertised subextent support. A prefix or middle read could therefore decode
only the requested output and accept `z_erofs_zstd_finish()` without checking
the remaining compressed stream. Corruption after the requested range could be
skipped.
P15-086 already authorizes partial ordinary reads only for LZ4, LZMA, and
Deflate. Its ZSTD result is `FULL_FALLBACK` because the partial candidate used
more temporary memory than full decode.
## Call Graph
For an ordinary mapped compressed read:
1. `z_erofs_do_read()` calls `z_erofs_decode_length()` with `mapoff` and
`want`.
2. `z_erofs_decode_length()` sets `partial=true` and `decoded_len=mapoff+want`
when the descriptor reports `supports_subextent` and the request ends before
the extent.
3. `z_erofs_decode_extent()` passes that length and mode to
`z_erofs_decompress()`.
4. `z_erofs_zstd_decompress()` fills the shortened output and calls
`z_erofs_zstd_finish()`.
5. `z_erofs_zstd_finish()` intentionally permits partial decoding without
requiring stream end. That behavior remains necessary for the separately
defined `EROFS_MAP_PARTIAL_REF` bounded-prefix path.
The smallest correct policy fix is to stop ordinary ZSTD reads at step 2:
ZSTD now advertises `.supports_subextent = 0`. `z_erofs_decode_length()` then
selects the full extent for ordinary prefix and middle reads. The explicit
`EROFS_MAP_PARTIAL_REF` branch still sets `partial=true` and remains unchanged.
## Changes
- Set the ZSTD descriptor capability to false in
`src/decompressor_zstd.c`; no finish validation was weakened or bypassed.
- Updated B27 assertions to preserve ZSTD partial-reference completion while
requiring ordinary ZSTD full fallback.
- Updated B28 source and extracted-policy assertions, host report, and QEMU
corruption decision so ZSTD is `FULL_FALLBACK`; LZ4/LZMA/Deflate policy is
unchanged.
## Verification
Commands and actual results:
- `git diff --check`: `PASS`.
- `sh -n repo-pre-15/tests/pre15/cases/B27-stream-tail.sh` and
`sh -n repo-pre-15/tests/pre15/cases/B28-partial.sh`: `PASS`.
- `PRE15_EVIDENCE_ROOT=/tmp/erofs-phase0-b28-20260818-r2 timeout -k 10 600
repo-pre-15/tests/pre15/run-host.sh B28-partial`: `PASS`; cleanup `PASS`,
target reached. Evidence:
`/tmp/erofs-phase0-b28-20260818-r2/20260818T070848Z-host-B28-partial-1780769-0/`.
The source audit reports `zstd=false`, ZSTD in `current_full_fallback`,
`current_partial=[deflate,lz4,lzma]`, and partial-reference preserved.
- `PRE15_EVIDENCE_ROOT=/tmp/erofs-phase0-b27-20260818 timeout -k 10 600
repo-pre-15/tests/pre15/run-host.sh B27-stream-tail`: `RUNNER_FAIL`, cleanup
`PASS`; the pre-existing B29 Deflate context-pool delta fails B27's frozen
exact-transform audit before the completion harness. This is not claimed as
ZSTD runtime evidence.
- P15-086 frozen gate result and policy were inspected, not rerun; its existing
recorded decision remains ZSTD `FULL_FALLBACK`.
The B28 host case generated and compared real EROFS fixtures and ran the
descriptor/decode-length source audit, but did not load a FreeBSD KLD or read
an image through the kernel. No full feature suite was run.
## Not Tested
`NOT_TESTED`: a real FreeBSD runtime read of an EROFS ZSTD image whose stream
is corrupted after an ordinary prefix or middle request. The required runtime
threshold is that the short ordinary read returns positive `EINTEGRITY` (97),
matching full fallback, while a valid ordinary prefix/middle/tail read matches
the source bytes.
`NOT_TESTED`: runtime confirmation that `EROFS_MAP_PARTIAL_REF` retains its
bounded-prefix semantics on a real image after this policy change.
## Risk
Ordinary ZSTD prefix and middle reads now decode the complete extent. This may
increase CPU or temporary output work relative to the previously incorrect
partial path, but it restores corruption visibility and matches P15-086 policy.
The changed tests do not alter test fixtures, image bytes, test environment, or
finish-error behavior.
## Runtime Gate
Before claiming Phase 0 runtime closure, run the existing focused B28 runtime
case with ZSTD enabled and verify valid prefix, middle, and tail reads, an
after-request-range corruption case returning `EINTEGRITY`, full corruption
returning `EINTEGRITY`, and the real partial-reference case. Record separate
`PASS`, `INFRA_BLOCKED`, or `NOT_TESTED` results; do not infer runtime behavior
from the extracted C harness.