Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
111199c
Run PR test workflow on pushes to main
zac Oct 9, 2026
ad325fc
Serialize workspace mutations and scope edit capture and rollback
zac Oct 9, 2026
7e81580
Bound tool-adapter output, harden search inputs, fix CRLF diffs, vali…
zac Oct 9, 2026
df52c6e
Bind root jail and authorization to the paths operations actually touch
zac Oct 9, 2026
715d0ba
Keep LocalFileSystem.remove a no-op for paths beneath a regular file
zac Oct 9, 2026
e1073dd
Fix checkpoint-store deadlock, torn-log recovery and cross-instance h…
zac Oct 9, 2026
316f1f4
Enforce filesystem limits atomically and fix in-memory, mount and wat…
zac Oct 9, 2026
ec1875f
Make three-way transaction merges structurally safe
zac Oct 9, 2026
9e08b68
Make filesystem accounting exact for local disks and dangling links
zac Oct 9, 2026
f48d987
Bound diff cost, speed up checkpoint paging, and budget remaining too…
zac Oct 9, 2026
a25ccea
Parse path syntax on UTF-8 bytes to close a root-jail escape
zac Oct 20, 2026
fdf6d39
Make path identity byte-exact and verify stored spellings
zac Oct 20, 2026
6b8c232
Add a release-mode benchmark harness for workspace operations
zac Oct 10, 2026
2e55b14
Store checkpoints as content-addressed trees in packed blobs
zac Oct 20, 2026
75055e9
Walk trees in one pass and make search byte-oriented
zac Oct 20, 2026
a292be4
Make transactions, preview and observation scale with the change
zac Oct 20, 2026
b7c8890
Capture checkpoints with the bulk traversal
zac Oct 20, 2026
815be72
Make restore and checkpoint diffs scale with the change
zac Oct 20, 2026
6238deb
Serialize FSEvents callbacks and teardown on a private queue
zac Oct 20, 2026
0c9f092
Cache LimitedFileSystem accounting and invalidate it from change signals
zac Oct 20, 2026
ec2f414
Make racy-metadata tests independent of scheduling
zac Oct 20, 2026
94ef94b
Validate the benchmark fixture before each scenario
zac Oct 20, 2026
4bdda03
Tolerate device renumbering when reusing persisted identities
zac Oct 20, 2026
764e018
Drop backward-compatibility code
zac Oct 20, 2026
08fbf81
Publish new history directories atomically and tidy capture edges
zac Oct 20, 2026
7a6e439
Keep entry equality exact and make the accounting cache cap configurable
zac Oct 21, 2026
7b41186
Rewrite the README for users
zac Oct 21, 2026
fa8ff68
Read directory metadata in bulk on Darwin
zac Oct 21, 2026
57dc842
Prune history at compaction, sync it at checkpoints, and page it
zac Oct 21, 2026
d7a4e47
Create parents in memory, return structured tool errors, drop a dead …
zac Oct 21, 2026
ba7ed8f
Never block a worker on a store lock, and hide in-flight write tempor…
zac Oct 21, 2026
92b3fe0
Make event and retry tests robust to a saturated scheduler
zac Oct 21, 2026
d179a4e
Authorize tool reads and hard links on the entry the caller named
zac Oct 21, 2026
19bb474
Fence FSEvents setup delivery instead of sleeping in the medium-tree …
zac Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
- ready_for_review
push:
branches:
- core-improvements
- main

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ references
Package.resolved
.DS_Store
.cursor

Benchmarks/Results/
51 changes: 51 additions & 0 deletions Benchmarks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Workspace benchmarks

`WorkspaceBenchmarks` measures Workspace operations against generated fixtures. It builds on macOS and Linux only and doesn't run as part of `swift test`.

## Running

```sh
swift run -c release WorkspaceBenchmarks --preset small --json Benchmarks/Results/before.json
swift run -c release WorkspaceBenchmarks --preset small --json Benchmarks/Results/after.json \
--compare Benchmarks/Results/before.json
swift run -c release WorkspaceBenchmarks --preset medium --filter transaction,limitedWrite
```

Scenario IDs have the form `backend/persistence/operation`, such as `local/directory/checkpointIncremental`. `--filter` takes comma-separated substrings of those IDs. `--compare` prints timing ratios and exact count differences against a saved report; compare the same preset on the same machine. `--json` rewrites the report after every scenario. Run `--help` for iteration counts, warmups and deadlines.

| Preset | Regular files | Size | Rough time at defaults |
| --- | --- | --- | --- |
| `small` | 1,000 | about 20 MiB | 2 to 5 minutes |
| `medium` | 10,000 | about 200 MiB | 10 to 30 minutes |
| `large` | 100,000, deeply nested | about 98 MiB | well over an hour |

The `large` preset runs only the local backend. Times depend on the filesystem and whether native watchers are available.

## Method

- Each scenario runs in a fresh child process, with one warmup and five measured samples by default. A child that exceeds the deadline (30 minutes by default) is killed and reported as failed.
- Fixture generation and per-sample setup are excluded from timing and counters. Write scenarios use independently prepared stores, so `write1001` always times exactly the 1,001st mutation.
- Without `--fixture-dir`, fixtures and scratch trees live in the temporary directory and are removed on completion or interrupt. `--fixture-dir PATH` generates a fixture there, or validates and reuses one already there. `--keep-fixture` preserves a generated one.
- If any scenario fails, the run exits nonzero after writing the successful results. Run outside a restrictive macOS sandbox, or the FSEvents scenarios fail.

| Scenario | What's timed | Setup excluded | Counter blind spots |
| --- | --- | --- | --- |
| `writeText`, `apply50`, `limitedWrite` | One recorded write, 50 edits, a quota-limited write with warm accounting | No-op preparation, file reset, priming the limit accounting | Checkpoint store; Limited's metadata traversal is visible |
| `transaction`, `transactionFirst` | Begin, one draft write, commit | Preparation; for `transaction` only, an initial begin and discard and a baseline checkpoint | Draft filesystem, checkpoint store |
| `preview` | One edit preview | Preparation | Draft filesystem |
| `checkpointFirst`, `checkpointIncremental` | First capture; capture after one change | Preparation; for incremental, the baseline and the change | Checkpoint store |
| `diff`, `restore` | Checkpoint-to-current diff or restore after one change | Preparation, baseline, change | Checkpoint store |
| `readCheckpoint`, `readCheckpointWarm`, `readCurrent` | Cold and primed checkpoint reads; a current read | Baseline; the first read for the warm variant | Checkpoint store |
| `search`, `glob` | Search for an absent literal; a `**/*` glob | Preparation | Glob internals; `globMatches` is visible |
| `history1000`, `history1000Cached` | Loading 1,000 mutations in a fresh directory-backed Workspace; reading cached in-memory history | Seeding 1,000 mutations | Checkpoint store |
| `write1001` | The 1,001st recorded directory-backed write | Preparation and 1,000 mutations | Checkpoint store |
| `eventsInitial`, `eventsExternal` | Starting observation; an external write until its event arrives | Preparation; for external, the initial observation | The external write itself; recaptures are visible |

## Reading the results

The table reports median and p90 wall time (linear interpolation between samples), backend bytes and calls read, `stat` and list calls, entries visited, glob matches, logical store bytes and files written, and memory: setup RSS high-water, its increase during the operation, RSS held with the result alive, and that held figure for the first run.

- Counters observe calls at the `FileSystem` boundary, not system calls. They exclude checkpoint-store I/O and a backend's internal glob traversal. Scoped walks report `walk` and `walkEntry` counters, and their content reads still count as reads.
- Store writes are estimated from directory metadata before and after the operation: appended growth or the final size of created and replaced files. Temporary and deleted files, repeated overwrites and OS write amplification don't show.
- After the first run, allocator reuse hides most of a result's memory, so the measured-sample memory figures can be near zero or slightly negative. Use the first-run column for a result's live footprint. Zero high-water growth can also mean reuse.
- The JSON report keeps every sample, including warmups, and each child's peak RSS. RSS is normalized to bytes on both platforms.
Loading
Loading