# FIXP finalization syncs the actual metadata directory

C++, Java, .NET and Rust synced the named parent of `<store>.finalized`, but not
the target's parent when a symbolic link redirected the metadata file into a
different directory. The correction syncs the actual target directory and, when
different, the named directory before acknowledging finalization. Application
save, replay and transport paths are unchanged; no lock is added.

## Confirmed failure

The probes open a real public file replay store, finalize one ID and check which
directory descriptors reach `fsync`. The target is an empty existing file or a
file created through a dangling metadata link. Each layout has an ordinary run
and a target-directory-only `EIO` fault. Plain metadata files calibrate the hook:
their directory sync is observed, the fault is honored and failure stays sticky.

The calibrated baseline at scan pin `54d69fd13` reports **ten passes, fourteen
failures and zero skips**. Every failing alias case accepts finalization, syncs
only the named directory and never attempts the target-directory sync. Thus a
fault configured for that target cannot change the old success answer.

| Public file replay store | Baseline passed | Baseline failed | Fixed passed |
| --- | ---: | ---: | ---: |
| C++ | 2 | 4 | 6 |
| Java | 2 | 4 | 6 |
| .NET | 4 | 2 | 6 |
| Rust | 2 | 4 | 6 |

.NET already refuses creation through a dangling metadata link; both of those
cases remain safe refusals. Its existing-target aliases reproduce the missing
directory sync. C++, Java and Rust reproduce it with both target layouts.

The normal C++ append-ownership target also registers four new directory cases.
Its baseline has **nine passes, four failures, 81 outer checks and zero skips**.
The fixture intercepts only this translation unit's journal sync calls, compares
directory identities by device and inode, and checks that a failed target sync
poisons duplicate and new-ID retries. The other ownership and allocation-failure
cases remain passing controls.

These checks reproduce missing directory syncs and acknowledgment behavior, not
a power cut. A newly created target entry without its containing directory sync
has an incomplete power-loss durability guarantee even when an immediate reopen
can read the record. Both directories matter: the named directory also contains
the symbolic metadata name and the replay file's own entry. Metadata names are
kept stable during finalization, as the existing store ownership contract requires.

## Correction and qualification

C++ and Java resolve the existing metadata target after the record is synced;
.NET follows the final file-link target; Rust canonicalizes the existing path.
Each syncs the actual parent, then the named parent if different. Existing
descriptor or identity ownership stays held through the directory syncs, and a
failed required sync follows the existing sticky-failure policy. Duplicate IDs
on a healthy handle retain their existing no-append behavior. The 28-byte format,
replay checkpoint ordering and Windows directory-sync policy are unchanged.

At hp pin `01dae0b19`, **all 24 public-store probes pass with zero skips**. The
registered C++ fixture passes **13 cases and 81 outer checks** under GCC 11.5.0,
14.2.1 and 15.2.1, and Clang 21.1.8. Existing C++ finalized-path, finalized-ID,
file replay and classic file-store fixtures pass in development and open builds;
development includes the private mmap path and finalization companions.

| Surrounding selection | Development passed | Open passed |
| --- | ---: | ---: |
| Java finalization, file stores and native bindings | 116 | 107 |
| .NET finalization, file stores and native bindings | 78 | 69 |
| Rust metadata append ownership | 8 | 8 |
| Rust inherited writer fences | 10 | 6 |
| Rust file-store library filter | 124 | 120 |
| Rust finalization library filter | 32 | 23 |

Every selection reports zero skips or ignored tests. Counts overlap and belong
to individual selections or Maven executions, not a combined unique-test total.
Development and open native libraries are rebuilt separately; native-loading
guards and edition-parity tests are included. Java and .NET open-boundary checks
pass, and the source scrub finds zero issues in the six changed engine/test files.

The redirected-directory probes additionally pass six cases each on Java 8, 11,
17, 21 and 25, and .NET 10.0.12: **36 passes, zero failures and zero skips**.
They use the fixed pin's hashed artifacts; Java version logs and .NET host traces
identify the selected runtimes. The surrounding .NET selections run on 8.0.31;
the six existing allocation/interruption cases also pass on 10.0.12.
These are Linux functional storage checks, not a full conformance sweep or
a hardware latency measurement.

Integration onto `133e730ab` leaves the entire Rust tree, managed main sources,
FIXP headers and file-journal implementation unchanged from the qualification
pin. The unrelated classic-FIX acceptor/store-path correction is not a retest of
that full native provider surface. At integrated pin `f698c9234`, the rebuilt
four-language probes pass all 24 cases again, and the registered C++ fixture
passes all 13 cases. The integrated raw logs are retained alongside the others.
Later evidence and documentation commits change no tested implementation bytes.

## Reproduction and evidence

`evidence/finalized-directory-sync-20261014/run-probes.sh` takes a session source
root, a fresh out-of-tree output root and `baseline` or `fixed`. Baseline mode
requires the calibrated fourteen red alias cases and passing controls; fixed
mode requires all 24 cases green. The probes exercise pure/public stores, not
native-provider availability. `run-fixed-and-qual.sh` runs the probes and the
surrounding development/open qualification under one outer shared CPU lease.
The runtime driver lives in `evidence/finalized-directory-runtimes-20261014/`.

The first scan probe at `a3aacbfdd` did not intercept .NET's explicit libc
P/Invoke lookup: even its plain-file controls saw no sync. That initial output
is retained but is not .NET regression evidence. The corrected probe installs
a process-local resolver before pure-store use, directing libc imports through
the shim and its real libc dependencies. Both .NET plain-file controls then
calibrate correctly. No resolver or fault hook is added to production code.

Compressed initial baseline, calibrated baseline, fixed, qualification and
runtime logs are tracked beside the drivers. Copies are retained under
`/home/yann/archive/libhft/finalized-directory-sync-20261014/` on hp; baseline
copies remain on scan too. Each has source pins and input hashes. scan uses a
locked worktree created with `wt` for this session, so its build root is no
longer an orphan without a corresponding worktree. Build outputs on either box
are under `/home/yann/build/codex-libhft-hp/libhft/finalized-directory-sync-20261014/`.
The remote scan checkpoint preserves the calibrated baseline pin. The archived
proposed patch predates application; the correction itself is in the four
language implementations, not a configuration to enable.
