Skip to content

feat(storage): enforce filesystem durability preflight before project mutation #776

Description

@DecisionNerd

Problem

ADR 0013 and the public durability contract require GraphForge to reject unproven filesystems before creating or mutating a project. Production open_or_initialize_project currently locks the supplied root and proceeds into generations/ creation and FORMAT writes without the required native publication-semantic probe.

Objective

Implement one Rust-owned, platform-aware filesystem durability preflight that proves the required local publication semantics before the first project-root mutation and is reused by every durable project publisher.

Debt / regime

  • Debt type: architecture, development, and test/proof.
  • Quality regime: A — deterministic storage correctness.

Requirements

  • Admit only supported local POSIX filesystems and local Windows NTFS volumes on storage that honestly honors write-through requests; reject ReFS, network, userspace, removable, cross-device, symlink-mediated, and unknown filesystems without guessing.
  • Run a private sibling create-lock-flush-publish probe before the target project root or CURRENT changes.
  • Prove file locking, same-filesystem atomic creation/replacement, file flush, stable locked-file identity, and the platform-native namespace durability barrier: directory fsync on POSIX; rename through an NTFS FILE_FLAG_WRITE_THROUGH file handle on Windows.
  • Coordinate absent-root and empty-root initialization through a parent-scoped creation lock so concurrent first openers cannot bypass the probe.
  • Return GF_UNSUPPORTED_FILESYSTEM before project mutation when required semantics cannot be proven.
  • Contain and bound probe artifacts; reject links, hard-link substitution, traversal, special files, and cross-device replacement.
  • Reuse the preflight for ordinary publication, recovery, deltas, compaction, checkpoints/revert, portable import, and every durable mutation entry point.
  • Keep CURRENT and complete immutable generations as the sole authority.
  • Document that GraphForge cannot compensate for storage hardware that falsely acknowledges write-through completion.

Acceptance Criteria

  • Unsupported/unproven filesystems, including Windows ReFS, fail before the root, FORMAT, generations/, or CURRENT changes.
  • Supported Linux, macOS, and Windows NTFS filesystems pass the native probe and initialize exactly once under concurrent first openers.
  • Injected lock, flush, replacement, namespace-durability, and cleanup failures return stable typed errors without an apparently initialized project.
  • Existing valid projects are revalidated at the documented lifecycle boundary without changing their selected generation.
  • Every durable public publisher consumes the same Rust preflight.
  • Probe work and evidence are bounded and content-free.

BDD Completion Scenarios

  • Given an unsupported filesystem, including Windows ReFS, when GraphForge creates or opens a durable project for mutation, then it returns GF_UNSUPPORTED_FILESYSTEM without project-root mutation.
  • Given two concurrent first openers on a supported location, when admission completes, then one complete generation becomes authoritative and both resolve the same CURRENT.
  • Given the platform-native namespace durability barrier cannot be completed, when preflight runs, then admission fails before durability can be acknowledged.
  • Given a probe dies or cleanup fails, when admission retries, then contained artifacts are handled deterministically and never become project authority.

Implementation Notes

Likely surfaces: project_generation.rs, project_publication.rs, project-root locking, platform filesystem helpers, GraphForge open/create, and the durability matrix. A filesystem-name allowlist, successful file flush, or undocumented Windows directory-handle flush alone is not proof. On Windows, the supported proof is NTFS-only: open the staging file with FILE_FLAG_WRITE_THROUGH, flush its contents, and perform the namespace rename through that handle.

Observability

Safe platform/filesystem class, phase, outcome/error, bounded counts/bytes, and elapsed time only. No graph contents or unrelated paths.

Security And Privacy

Use unpredictable contained sibling paths and revalidate identity after locking. Never follow links or inspect unrelated filesystem state.

Testing

Deterministic admission/error tests, multiprocess barriers, phase failure injection, malicious entries, and required native Linux/macOS/Windows NTFS CI. #749 remains the persistent-media oracle.

Documentation

Update ADR 0013 implementation status, concurrency/recovery architecture, durability limitations, and testing/runbooks.

Non-Goals

Remote/object-store durability, best-effort mode, ReFS durability, benchmarks, or guaranteeing dishonest hardware flush acknowledgements.

Related Issues

Canonical tracker #747; contract #748; native oracle #749; native primitive child #779; lifecycle integration child #780; delta publication #752; final certification #756.

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreCore source code changesenhancementNew feature or requesttestingTest coverage and testing infrastructure

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions