Repository navigation
VFS step 1: File.read/write/exist?/file?/directory?/size over a boot fixture - #21
Merged
Merged
Conversation
This was referenced Oct 4, 2026
sam-xif
pushed a commit
that referenced
this pull request
Oct 10, 2026
`intMetaId`/`strMetaId` are now `opaque` definitions read off the prelude-booted heap, so adding a bootstrap class or boot-time eigenclass no longer requires editing `State.lean` (PR #21 moved them 76/85 -> 87/96 by hand). `opaque` keeps proofs from unfolding the prelude, which the kernel cannot reduce. The values stay 76/85, so the corpus is unaffected, and a new `#eval` names the offending id if the derivation lands on 0 or a non-class object. `ConstantReachControls`'s scratch heap size is now `Boot.mainId + 3` for the same reason. Gate: `run_typed_ratchet.sh` GREEN, 125/125 clinks, 256 agree / 0 disagree, 131/263 corpus rungs, 46/46 negative controls. Authored by Nori, an agent.
…fixture Implements the first shippable step of issue #7: the symbolic virtual filesystem. A file is a heap object (`Payload.file`/`Payload.dir`), the fixture is initial data H0' allocated at boot, path resolution is one pure total walk, and every unmodeled operation is a named Unsupported rather than a guess or a fabricated Errno. - New bootstrap classes IO, File < IO, Dir; new payload variants file/dir. - VFS.components/walk/resolve/lookup in Heap.lean; fixture allocated after main and the two realized eigenclasses, with `vfsBase` derived from `classTable.length` so new classes shift the fixture ids automatically. - Builtins/FS.lean: the six File operations plus IO.read/IO.write and Dir.exist?, discharged through the prelude's class-method path. File.write mutates inode bytes in place and returns the byte count; inspect/to_s of a raw file/dir object gate rather than guess CRuby's path-bearing rendering. - FS singleton methods are installed on their constants' eigenclasses in Prelude.boot (like Exception.exception), so they use ordinary dispatch and add no `send` special case. Only real CRuby class methods are installed, so Dir.read-style typos still NoMethodError exactly as CRuby does. - Repaired the boot-shift the new classes caused: intMetaId/strMetaId (prelude heap ids) 79/88 -> 87/96, ConstantReachControls' concrete heap/Next id, the runFS_frame/pathArg?/VFS.lookup root-frame lemmas, and bootGlobalConsts. Evidence: lake build rubycore + active-ratchet green, #guard bootOkB passes, run_typed_ratchet.sh prints RATCHET GREEN, check-proofs.sh passes, and the step-1 surface agrees with CRuby byte-for-byte. The hermetic difftest "vfs" envelope and un-gating the bootstraptest filesystem family (issue #8) are the next step. Authored by Nori (agent).
The first cut of `VFS.walk` treated `..` as a no-op, so
`File.read("/tmp/vfsdata/../readme.txt")` gated where CRuby answers. Store the
parent in the `dir` payload (root's is `none`) and climb it, which is the one
definition issue #7 asks for. `.`, `..`, `./c` and `a/b/../c` now agree with
CRuby byte-for-byte.
Authored by Nori (agent).
sam-xif
force-pushed
the
nori/vfs-step1-file-read-write
branch
from
October 10, 2026 04:04
2da15f8 to
1fc30e4
Compare
sam-xif
pushed a commit
that referenced
this pull request
Oct 10, 2026
`intMetaId`/`strMetaId` are now `opaque` definitions read off the prelude-booted heap, so adding a bootstrap class or boot-time eigenclass no longer requires editing `State.lean` (PR #21 moved them 76/85 -> 87/96 by hand). `opaque` keeps proofs from unfolding the prelude, which the kernel cannot reduce. The values stay 76/85, so the corpus is unaffected, and a new `#eval` names the offending id if the derivation lands on 0 or a non-class object. `ConstantReachControls`'s scratch heap size is now `Boot.mainId + 3` for the same reason. Gate: `run_typed_ratchet.sh` GREEN, 125/125 clinks, 256 agree / 0 disagree, 131/263 corpus rungs, 46/46 negative controls. Authored by Nori, an agent.
jiro-by-nori Bot
added a commit
that referenced
this pull request
Nov 6, 2026
`intMetaId`/`strMetaId` are now `opaque` definitions read off the prelude-booted heap, so adding a bootstrap class or boot-time eigenclass no longer requires editing `State.lean` (PR #21 moved them 76/85 -> 87/96 by hand). `opaque` keeps proofs from unfolding the prelude, which the kernel cannot reduce. The values stay 76/85, so the corpus is unaffected, and a new `#eval` names the offending id if the derivation lands on 0 or a non-class object. `ConstantReachControls`'s scratch heap size is now `Boot.mainId + 3` for the same reason. Gate: `run_typed_ratchet.sh` GREEN, 125/125 clinks, 256 agree / 0 disagree, 131/263 corpus rungs, 46/46 negative controls. Authored by Nori, an agent. Co-authored-by: Nori <contact@tilework.tech>
jiro-by-nori Bot
added a commit
that referenced
this pull request
Nov 7, 2026
The control is a hand-built heap whose highest live index is the main object at Boot.mainId. Sizing it at mainId + 3 grew the heap by two slots and moved the fresh class' id to mainId + 3 (50), even though the literal it replaces (48) is mainId + 1. Use mainId + 1 so the de-pinning keeps the same heap and the same expected fresh id, and describe the present layout rather than the pre-#21 one. Addresses the review on #84. Co-authored-by: Nori <contact@tilework.tech>
jiro-by-nori Bot
added a commit
that referenced
this pull request
Nov 8, 2026
`intMetaId`/`strMetaId` are now `opaque` definitions read off the prelude-booted heap, so adding a bootstrap class or boot-time eigenclass no longer requires editing `State.lean` (PR #21 moved them 76/85 -> 87/96 by hand). `opaque` keeps proofs from unfolding the prelude, which the kernel cannot reduce. The values stay 76/85, so the corpus is unaffected, and a new `#eval` names the offending id if the derivation lands on 0 or a non-class object. `ConstantReachControls`'s scratch heap size is now `Boot.mainId + 3` for the same reason. Gate: `run_typed_ratchet.sh` GREEN, 125/125 clinks, 256 agree / 0 disagree, 131/263 corpus rungs, 46/46 negative controls. Authored by Nori, an agent. Co-authored-by: Nori <contact@tilework.tech>
jiro-by-nori Bot
added a commit
that referenced
this pull request
Nov 8, 2026
The control is a hand-built heap whose highest live index is the main object at Boot.mainId. Sizing it at mainId + 3 grew the heap by two slots and moved the fresh class' id to mainId + 3 (50), even though the literal it replaces (48) is mainId + 1. Use mainId + 1 so the de-pinning keeps the same heap and the same expected fresh id, and describe the present layout rather than the pre-#21 one. Addresses the review on #84. Co-authored-by: Nori <contact@tilework.tech>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements step 1 of issue #7 — the symbolic virtual filesystem — which is the first shippable slice of that ship order ("step 1 alone is a complete feature"). A file is a heap object, the fixture is initial data, path resolution is one pure total walk, and an unmodeled operation is a named
Unsupported.Closes: part of #7 (step 1). Follow-ups for the remaining ship-order steps are listed below.
What changed
Model (
RubyCore/)Payload.file (bytes)/Payload.dir (entries) (parent)(Heap.lean). A directory is distinguished by payload, never a string convention;dirstores ordered(basename × ObjId)children plus aparent, so./.., relative-path walking and listing share one definition.IO,File < IO,Dir, appended afteryielderId.mainId44 → 47.H₀′: five objects allocated after main and the two realized eigenclasses.vfsBaseis derived (classTable.length + 3), so a new bootstrap class shifts the fixture ids without a second edit.VFS.components/walk/resolve/lookup: one pure, total resolution from the fixture root...climbs the stored parent (root stays put), matching CRuby ona/b/../c,./cand trailing-slash forms; only absolute paths resolve at step 1 (thecwdis Proposal: virtual filesystem with symbolic and dynamic modes for the Ruby semantics #7 open question 2).Builtins/FS.lean:File.read/write/exist?/file?/directory?/size, plusIO.read/IO.writeandDir.exist?. Missing path, directory passed toread/size, non-String path, and any other shape return a namedUnsupported— nothing guesses, nothing fabricates anErrno(classes/messages are step 7).File.writemutates inode bytes in place and returns the byte count.Repr/Trace/nativeReprOwnergate inspecting or stringifying a raw file/dir object rather than guess CRuby's path-bearing rendering.Prelude.boot(likeException.exception), so they dispatch through ordinary lookup — nosendspecial case and no metatheory ripple. Only class methods that exist in CRuby are installed, soDir.read-style typos still reach the prelude'smethod_missingand answerNoMethodErrorexactly as CRuby does. The prelude'sFile.basename/dirname/extname/joinare unchanged (module File→class Fileto reopen the boot class).Boot-shift repairs the new classes forced
intMetaId/strMetaId(prelude-booted heap ids) 79/88 → 87/96;#guard bootOkBcatches a stale value. Deriving them from the heap is tracked as debt (see follow-up).ConstantReachControls' concrete control heap grew one object; itsNextconstant now points at.ref 48.runFS_frame+pathArg?/VFS.lookupframing lemmas joinrootFrameLem;runModules_frame's terminal is nowrunFS.bootGlobalConstsgainsIO/Dir.Verification (empirical)
lake build rubycoreand the active-ratchet target: green.#guard bootOkB: passes../scripts/run_typed_ratchet.sh:RATCHET GREEN(validateD_safe_run passes for the enabled clinks)../scripts/check-proofs.sh: passes; every theorem rests onpropext + Classical.choice + Quot.sound../scripts/check-isolation.sh:Ratchet/still does not seeRubyCore/.File.read/size/exist?/file?/directory?(fixture and missing path),Dir.exist?,File.write-then-read,File.basename, and../.resolution (/tmp/vfsdata/../readme.txt).File.open(no block, step 2) and a missing path gate with named reasons.Not in this PR (next steps, per #7 ship order)
"vfs"fixture envelope +advisorytier, and un-gating thebootstraptestfilesystem family (bootstraptest filesystem programs are not hermetic and fail the round-trip (gated out for now; addressed by #7) #8). Step 1 currently agrees with CRuby in direct probes but the corpus remains gated until the fixture is threaded through the harness.File.open,IO,gets,pos,rewind) — step 2+.intMetaId/strMetaId/fixture ids from the heap instead of pinning;Errnoclasses and message fidelity (step 7).Authored by Nori, an autonomous agent. Follow-up debt found while landing this is tracked in #22.