Skip to content

FABRIC-BLOB-0A: filesystem realization of the fabric M0 durable origin - #11319

Closed
briansrls wants to merge 5 commits into
mainfrom
session/fabric-blob-0a-filesystem-origin
Closed

briansrls wants to merge 5 commits into
mainfrom
session/fabric-blob-0a-filesystem-origin

Conversation

@briansrls

@briansrls briansrls commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

First lane of the blob-backed evidence store. It is a second realization of the existing fabric M0 origin contract, beside R2, over a host directory tree. It is not a new store vocabulary: gunbc.fabric_m0_commit and gunbc.fabric_m0_completion judge it exactly as they judge the R2 origin.

What lands

  • gunbc.fabric_m0_origin_filesystem
    • Layout. <root>/objects/<directories...>/<name> holds installed objects; <root>/staging/ holds unique staging files. A content-addressed object is <root>/objects/sha256/<64-hex digest>.
    • No directory creation. The origin root, objects/, every intermediate key directory and staging/ must already be real, non-symlink directories created by host convergence. Otherwise put refuses and fetch is unavailable.
    • Keys. Keys are admitted directory-entry names, so lexical traversal is refused. The effectful entries take key: NonEmptyStr.
    • Put.
      • Writes a unique staging file (cp, sync), then ln, which is create-if-absent by construction, then sync on the key's already-established directory.
      • A failed link is classified by listing that directory: listed means occupied, unlisted means refused, unlistable means unknown. It is never classified by ln's exit status.
      • Staging cleanup is best effort.
    • Fetch.
      • Absence is established only by a listing that succeeded.
      • The listed leaf must be a regular file and not a symbolic link.
      • The object and its directory are fsynced before a read is staged; any failure is unavailable, so an unknown put is never laundered into a confirmation.
      • The fetch copies into its own directory and reads through read_origin_staged_file, the sole reading mint.
  • OriginPutOutcome moves from gunbc.cloudflare.r2_origin_object into gunbc.fabric_m0_origin_readback, beside OriginFetchOutcome.
  • extdeps.shell additions: shell.Sync.Path (coreutils sync -- PATH, an fsync of one named file or directory) and shell.Test.IsSymbolicLink (POSIX test -h, not following the link).

Stated limits

  • Durability is fsync on one host. It says nothing about the disk's write cache and survives no host loss; that is FABRIC-BLOB-0B's job.
  • Unguarded race: a symbolic link substituted between the directory/leaf observation and the effect that follows is not prevented. Until a beneath-root resolution capability exists (openat2 RESOLVE_BENEATH or directory file descriptors), the host binding owes single-principal ownership of the origin root.
  • The fetch's staged copy is left in place, as the R2 fetch's is.
  • Digests come from host sha256sum.

Not in this PR

  • srv1/srv2 replication, the service unit and host convergence (FABRIC-BLOB-0B, not authorized for hosts yet).
  • SCM manifest blob references and the ref compare-and-set (SCM-BLOB-0, coordinated with gunbc#11317's CAS provider gate).

Verification (by execution, binary built from main fb0155b)

  • fabric_m0_origin_filesystem_witness_test: 9/9 hermetic. Covers key admission, directory and leaf standing, link and listing decisions, fetch absence, and the unknown-put composition through object_readback_of_origin_put and readback_digest_verdict: undetermined when unstabilized, satisfied when stabilized.
  • fabric_m0_origin_filesystem_wet_witness_test: 10/10 against a real throwaway root.
    • A stored put reads back and satisfies; the same bytes twice are already present, with staging left empty.
    • Different bytes never replace an occupied key and fail the verdict.
    • An absent key under an established directory is absent.
    • Refused or unavailable without creating anything:
      • staging/ present with objects/ absent: put refuses and objects/ is not founded;
      • a key directory that was never established;
      • a symlinked key directory: nothing lands outside;
      • a lexically escaping key;
      • a root that is itself a symlink.
    • A digest leaf symlinked to an outside file holding the expected bytes: fetch unavailable, verdict undetermined.
  • Regression: cloudflare_r2_origin_object 14/14, fabric_m0_origin_commit 10/10, fabric_m0_commit 13/13, fabric_m0_completion 29/29.
  • Mutations:
    • Classifying an unlisted failed link as occupied turns the link claim red.
    • Letting an unstabilized fetch read turns the laundering claim red.
    • Skipping the leaf observation turns the symlinked-leaf control red.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Yb9agVcWYWzjhPsJ42XQAk

gunbc-ci-auto-heal and others added 2 commits September 13, 2026 22:17
gunbc.fabric_m0_origin_filesystem produces the fabric M0 origin contract's
answers (OriginPutOutcome, OriginFetchOutcome) from a directory tree on a
host, so gunbc.fabric_m0_commit and gunbc.fabric_m0_completion judge it
exactly as they judge the R2 origin:

- keys are sequences of admitted directory-entry names; a SHA-256 content
  address is sha256/<2>/<2>/<hex>;
- put: unique staging file, cp, fsync, mkdir, hard link (create-if-absent by
  construction), fsync the key's directory; a failed link is classified by a
  listing of that directory, never by ln's exit status;
- fetch: walks the key's segments with listings, so absence is established
  only by a listing that succeeded; stages its own copy and reads it through
  read_origin_staged_file, the sole reading mint.

OriginPutOutcome moves from gunbc.cloudflare.r2_origin_object to
gunbc.fabric_m0_origin_readback beside OriginFetchOutcome: the shape is the
interface's, and a second realization no longer imports a vendor to answer.

extdeps.shell gains shell.Sync.Path (coreutils sync -- PATH, fsync of one
named file or directory).

Witnesses: fabric_m0_origin_filesystem 6/6 (hermetic), 6/6 wet against a real
throwaway root (stored put reads back and satisfies readback_digest_verdict;
same bytes twice already present; different bytes never replace an occupied
key and fail the verdict; absent key with missing directories; root without
objects/ unavailable, never absent; escaping key refused). Regression:
cloudflare_r2_origin_object 14/14, fabric_m0_origin_commit 10/10,
fabric_m0_commit 13/13, fabric_m0_completion 29/29. Mutation: reading an
unlisted failed link as already present turns the link claim red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Yb9agVcWYWzjhPsJ42XQAk
…tch, symlink refusal

Review repairs on the filesystem realization of the fabric M0 origin:

A. The realization creates no directory. Every directory a key passes
   through (objects/, intermediate segments) and staging/ must already be
   established by host convergence; otherwise put refuses and fetch is
   unavailable. Content keys are sha256/<hex> under one established
   directory, so the only directory fsynced after a link is the key's own,
   already-established parent.
B. A fetch fsyncs the installed object and its directory before staging a
   read; if either fails the fetch is unavailable and no reading is minted,
   so an unknown put (link without directory fsync) is never laundered into
   a confirmation. A later fetch that stabilizes is the reconciliation.
C. Every directory on a key's path is observed to be a real directory and not
   a symbolic link (test -d, and the new shell.Test.IsSymbolicLink = POSIX
   test -h) before any effect. The claim is stated at its grain: lexical
   traversal and symlinked components refuse; a link substituted between
   observation and effect is the host binding's obligation until a
   beneath-root resolution capability exists.
D. put/fetch take key: NonEmptyStr; no placeholder key is ever minted.

Witnesses: hermetic 8/8 (incl. unknown put + unstabilized fetch =
undetermined, + stabilized fetch = satisfied); wet 8/8 (incl. staging present
and objects absent refuses without founding objects/, never-established key
directory unavailable and not created, symlinked sha256/ refuses with nothing
landing outside). Regression: cloudflare_r2_origin_object 14/14,
fabric_m0_origin_commit 10/10. Mutation: letting an unstabilized fetch read
turns the laundering claim red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Yb9agVcWYWzjhPsJ42XQAk
@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed the HOLD at 96d1caa against head 46f1a40.

A. No directory creation. Put and fetch require every directory on the key's path (objects/, intermediate segments) and staging/ to already be real directories; otherwise put refuses and fetch is unavailable. Content keys are now sha256/<hex> under one convergence-established directory. Wet control: staging/ present and objects/ absent refuses and does not create objects/.

B. Fetch fsyncs the installed object and its directory before staging a read; failure is OriginFetchUnavailable. Hermetic control composes through object_readback_of_origin_put and readback_digest_verdict: unknown put plus unstabilized fetch is undetermined, plus stabilized fetch is satisfied. Mutation letting an unstabilized fetch read turns it red. A real directory fsync failure is not drivable wet; that arm is covered only hermetically, over the same decision function.

C. Each directory component is checked with test -d and the new shell.Test.IsSymbolicLink (POSIX test -h); a symlinked component refuses. The module's claim is lowered to lexical traversal plus observed-real-directory structure; a substitution between observation and effect is declared the host binding's obligation until a beneath-root resolution capability exists. Wet control: sha256/ as a symlink to an outside directory refuses, nothing lands outside.

D. put_filesystem_origin_object / fetch_filesystem_origin_object take key: NonEmptyStr; no placeholder key.

Staging cleanup is now stated as best effort. Runs on a binary built from main fb0155b: hermetic 8/8, wet 8/8, cloudflare_r2_origin_object 14/14, fabric_m0_origin_commit 10/10.

…fect

Review follow-up on the remaining part of C. The origin root itself is now in
the observed directory population for put and fetch, so a root that is a
symbolic link refuses. A fetch observes the listed object leaf with
OriginObjectLeafStanding (test -h, then test -f) before it syncs or copies it:
a symbolic link or a non-regular file is OriginFetchUnavailable and no reading
is minted, so bytes outside the origin tree can never satisfy a readback.

Witnesses: hermetic 9/9 (adds leaf standing arms and the decision refusing a
symlinked or non-regular leaf over a staged fixture); wet 10/10 (adds a root
that is a symbolic link, put refused / fetch unavailable / nothing lands in the
target tree; and a digest leaf symlinked to an outside file holding exactly the
expected bytes, fetch unavailable and verdict undetermined). Mutation: skipping
the leaf observation turns the symlinked-leaf control red while the positive
control stays green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Yb9agVcWYWzjhPsJ42XQAk
@briansrls

Copy link
Copy Markdown
Contributor Author

Addressed the remaining root/leaf portion of C at head af5ece6. The origin root is now in the observed directory population for put and fetch. A fetch observes the listed leaf with OriginObjectLeafStanding (test -h, then test -f) before sync or copy, and a symlinked or non-regular leaf is unavailable. New wet controls: a root that is a symlink (put refused, fetch unavailable, nothing lands in the target tree), and a digest leaf symlinked to an outside file with exactly the expected bytes (fetch unavailable, verdict undetermined). Mutation skipping the leaf observation turns that control red. Hermetic 9/9, wet 10/10. The PR body is rewritten to match the current source (sha256/<hex>, no directory creation, current counts).

gunbc-ci-auto-heal and others added 2 commits September 14, 2026 16:34
… lane

Every function in fabric_m0_origin_filesystem_wet_witness_test writes into a throwaway temp
directory it creates and removes, and mktemp has no hermetic arm - so under the hermetic envelope
each one is planned and then never reaches its subject, which the floor reports as an unenrolled
route gap rather than a verdict. The file is excluded from the discovery corpus and its ten
identities are scheduled on the local-repo wet lane, where the floor runs each member wet and joins
the observed terminals back at identity grain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@briansrls

Copy link
Copy Markdown
Contributor Author

CI state at ed219dabf11 (wet-lane enrolment + current main merged).

Fixed here: the ten fabric_m0_origin_filesystem_wet_witness_test identities were planned by the floor and could never reach their subject (mktemp has no hermetic arm), which the floor reported as unenrolled route gaps rather than verdicts. They are now excluded from the discovery corpus and scheduled on the local-repo wet lane, where the floor runs each member wet and joins terminals back at identity grain. Those gaps are gone from the run.

Two gates still refuse, and neither is repaired by this branch:

  1. namespace-wave-admission — 45 unadjudicated deltas. The roster is an authored const in src/v1/stage0/src/namespace_wave_admission.rs, empty by default, and a wave authors its rows and removes them once consumed.
  2. floor — PureProducerShareProducerModuleOutsideSubject for v2.test.execution.emit_on_demand_match_loop_fold_family_witness.mlf_family_primary_emitted, whose inner cause is AmbiguousBareNameRead in that witness's own scope (sites=1). I did not establish whether this branch introduces the ambiguity or inherits it.

heal-generated-artifacts and required-witnesses-build pass.

🤖 Generated with Claude Code

@briansrls

Copy link
Copy Markdown
Contributor Author

Closing unmerged to wind down the session. Tracked in #11399 together with the 0B lane, since fd859756ff0 already contains this branch. The branch session/fabric-blob-0a-filesystem-origin (ed219dabf11) is left in place. Its prior source sign-off at af5ece6b795 stands; what blocks it is the wave-admission roster and a floor refusal in an unrelated v2 witness.

@briansrls briansrls closed this Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant