Repository navigation
Set and report permission modes on Branch file calls (#442) - #445
Merged
Merged
Conversation
fs.write and fs.mkdir, and the write and mkdir changes of fs.apply, take an
optional integer `mode`. A new file gets it, else 0o644; an existing file
keeps its mode unless one is given. A new folder gets it, else 0o755; new
parents get 0o755 and an existing folder keeps its mode, as `mkdir -p -m`
does. A new `{ op: "chmod", path, mode }` change sets an existing entry's
mode. fs.stat now reports `mode` (read with read_portable: no object read
for inline metadata).
A `mode` that is not an integer from 0 to 0o7777 is InvalidInput. A mode
LayerFS cannot store (set-user-ID or set-group-ID, sticky on a file) is
InvalidInput with detail { reason: "Mode", path, mode }, as project.init
reports it. A symlink has no mode of its own: chmod of one is NotFile.
Before this a supplied mode was silently dropped. Other unknown change
fields are still ignored.
JS SDK: the last argument of fs.write and fs.mkdir is a message string, as
before, or { message?, mode? }. CLI: `--mode <octal>` on fs write and fs
mkdir. api/how-to-use/agent.md documents modes, chmod and the options.
Store format unchanged. No test deleted. relink_commit passes `None` for
the new Mutation::write argument; the sdk_methods golden adds `mode` to
its two fs.stat lines. New test: core/crates/layerfs-api/tests/fs_mode.rs.
Production LOC: 102160 -> 102248 (delta +88)
core 96788 -> 96863 (+75: layerfs-store-service 10009 -> 10066,
layerfs-api 2293 -> 2311); api 5372 -> 5385 (+13: @layerfs/agent
836 -> 844, @layerfs/cli 540 -> 545); reference absent (retired R9c;
last counted 65,417 at tree 498dd19). Counted with
tools/production_loc.py --json --root on git archive extracts of the
parent c77281e and the staged tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
api/agent/sdk/test/verify/fs_mode_real.mjs drives the real native binding
under the E2E launcher: fs.write/fs.mkdir with { message, mode } and with a
plain message, fs.apply write/mkdir modes and chmod, and fs.stat's `mode`.
A mounted Workspace of the Branch shows the same modes through FUSE
(`stat -c %a`, and the new scripts run), and a chmod made in the Workspace
and committed reads back through fs.stat. Refusals (set-user-ID and sticky
on a file with reason Mode, a text mode, a non-object option) commit
nothing.
Passed once on Linux (worktree.py run, bundle
build-linux-ef3909ed42c24038b2b0f4c500de457f, run
ba95a5161f3e4baa94ab028cccb3d00d, 4 s).
Production LOC: 102248 -> 102248 (delta 0)
Test only. core 96863, api 5385, unchanged; reference absent (retired
R9c; last counted 65,417 at tree 498dd19). Counted with
tools/production_loc.py --json --root on git archive extracts of the
parent f9f154c and the staged tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's layer split (#463) moved the crates and packages this PR changes. Git carried every edit to its new path; the two conflicts were this PR's new test files, added inside renamed directories. They now live at engine/crates/layerfs-api/tests/fs_mode.rs and api/agent/test/verify/fs_mode_real.mjs; the latter's usage comment names its new path. No source conflict needed a choice. Checked on the merged tree (Linux arm64, tools/worktree.py, each run under the 2-minute limit): layerfs-api fs_mode, sdk_method_golden, write_refusals, method_refusal_order and the 25 other fast tests using these calls, the moved merge_report, concurrent_commits and lane_merge, the five slow ones, and layerfs-store-service's tests all pass; rustfmt and Clippy -D warnings clean; api/agent/test/calls.mjs (38) and api/cli/test/cli.test.mjs (74) pass; fs_mode_real.mjs passed once through the rebuilt native bundle (run 23860de121af405ca2e6315b8ef48ee4). Production LOC: 102248 -> 102250 (delta +2) First-parent comparison (20b0551 -> this merge); the +2 is main's. Against main 3e5f3a6 (102162) this branch adds +88: engine layerfs-api 1913 -> 1931, layerfs-store-service 10009 -> 10066; api @layerfs/agent 836 -> 844, @layerfs/cli 540 -> 545. Merged scopes: api 2646, core 38241, engine 61363; reference absent (retired R9c; last counted 65,417 at tree 498dd19). Counted with the merged tree's tools/production_loc.py --json --root on git archive extracts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
yifanxuaaa
added a commit
to Jackmeson1/layerfs
that referenced
this pull request
Oct 27, 2026
) Main gained Ephemeral-AI-Lab#418/Ephemeral-AI-Lab#419 merge tests and Ephemeral-AI-Lab#445 since this branch's base caebd26. The only conflict was engine/crates/layerfs-api/tests/ merge_by_serial.rs, where both sides appended tests after the same test (a_new_file_is_dropped_once_every_link_is_lost). Resolved by keeping both: this branch's helper changes, then main's added tests, then this branch's added tests. No line of either side was changed. Production source merged without conflict. Production LOC: 102199 -> 102527 (delta +328) First-parent comparison (bdef701 -> this merge); the +328 is main's. Against main 303246d (102528) this branch is delta -1: core layerfs-content 26058 -> 26057. Merged scopes: api 2659, core 38334, engine 61534; reference absent (retired R9c; last counted 65,417 at tree 498dd19). Counted with tools/production_loc.py (blob 3341e4d) --json --root on git archive extracts of the parent, the merged tree and main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Closes #442.
The Branch file calls always created files as 0644 and folders as 0755, silently dropped any
modea caller passed, andfs.statdid not report a mode. This adds modes end to end.What changes
modeon create:fs.write,fs.mkdir, and thewrite/mkdirchanges offs.applytake an optional integermode(e.g.0o755).mode, else 0644. An existing file keeps its mode unlessmodeis given.mode, else 0755. New parent folders get 0755 and an existing folder keeps its mode, asmkdir -p -mdoes.chmodchange:{ op: "chmod", path, mode }infs.apply.fs.statreportsmode, read withread_portable(no object read for inline metadata).InvalidInput.InvalidInputwithdetail { reason: "Mode", path, mode }, asproject.initreports it. Sticky on a folder is allowed, as in Init.chmodof a symlink isNotFile.fs.write/fs.mkdircopy all their call arguments into the change, so a strict check would break them.fs.writeandfs.mkdiris a message string, as before, or{ message?, mode? }.--mode <octal>onfs writeandfs mkdir.api/docs/agent.mdcovers modes,chmodand the options.No Store format change: every entry already stores a mode, and the Workspace engine already validates modes on create and chmod. Mode-only changes already commit and merge correctly (#352 F-052).
Commits
f9f154c8fffeature. Production LOC: 102160 -> 102248 (delta +88): core +75 (layerfs-store-service +57, layerfs-api +18), api +13 (@layerfs/agent +8, @layerfs/cli +5).20b05510d2end-to-end test only. Production LOC: 102248 -> 102248 (delta 0).d8d6f54c18merge of main3e5f3a627c(layer split D8 · Refactor core/ into core, engine and api layers #463): the edits followed the moves; only the two new test files needed placing. Production LOC: 102248 -> 102250 (+2, main's own); against main this branch adds +88. All checks below were rerun on the merged tree and pass.Tests
No test deleted or weakened.
relink_commit.rspassesNonefor the newMutation::writeargument. Thesdk_methodsgolden addsmodeto its twofs.statlines.All runs below are on Linux arm64 via
tools/worktree.py, each under the 2-minute limit:engine/crates/layerfs-api/tests/fs_mode.rs: 2 tests, pass.layerfs-apitest that uses these calls (30 binaries, including the slow ones) andlayerfs-store-service's own tests: all pass.-D warningson both crates: clean.api/agent/test/calls.mjs(38 cases, 2 new) andapi/cli/test/cli.test.mjs(74, including 2 new--modeusage errors): pass.api/agent/test/verify/fs_mode_real.mjs, through the real native addon: passed once. It coversfs.statmodes after each call, the refusals,stat -c %ain a mounted Workspace (FUSE) for all nine paths, and a Workspacechmod+ commit read back throughfs.stat.Not run: the macOS/Windows worker routes. They forward the same SDK calls to a Linux worker and were not changed.
🤖 Generated with Claude Code