OXYGENHUB
# abdbc768c6e8 oxygen / docs / backlog-overnight-4.md
8.8 KiB · Markdown · last changed Backlog 4: the other planned work, for when the speed items are blocked 1 month ago renderedsource blame history raw
1
# Overnight backlog 4: beating Git on the Linux tree
2
3
Loop 3 made oxy usable on the Linux kernel. This loop aims to make it
4
faster than Git wherever the model allows it, with the kernel tree as the
5
yardstick. Correctness is never traded for speed: every item keeps its
6
tests, and the test builds that compare an incremental structure with a
7
full computation stay on.
8
9
## The yardstick
10
11
The Linux tip on Earth (`~claude/bench/linux`, 95 943 files, 1.8 GB):
12
`o` is the oxy repository and `g` the Git one. Git is 2.53.
13
14
| Operation | oxy (2026-09-30) | Git | Target |
15
|---|---:|---:|---|
16
| init and first commit | 38.5 s, 4.4 GB peak RSS | 38.8 s | under Git, under 2 GB |
17
| status, clean | 0.41 to 0.43 s | 0.26 to 0.32 s | at or under Git |
18
| status, one file edited | 1.26 to 1.39 s | 0.26 to 0.29 s | at or under Git |
19
| diff, one file | 1.19 to 1.45 s | 0.16 to 0.25 s | at or under Git |
20
| commit, one file | about 3.1 s | 0.45 s | under 0.5 s |
21
| status, diff and commit, 1 000 files | 3.9, 2.8 and 4.9 s | 0.41, 0.95 and 0.57 s | at or under Git |
22
| log -n 100 | 1.39 s | 0.01 s | under 0.05 s |
23
| blame MAINTAINERS | 1.18 s | 0.09 s | at or under Git |
24
| checkout to the first state and back | 2.2 to 2.8 s | 0.42 to 0.47 s | at or under Git |
25
| fsck | 22.1 s | 13.1 s | at or under Git |
26
| gc | 39.7 s | 102.8 s | stays ahead |
27
| store after gc | 324 MB | 295 MB | at or under Git |
28
29
Where one-file status time goes now (Earth, loaded):
30
- index load: 0.16 to 0.28 s
31
- walk: 0.45 to 0.7 s
32
- manifest check before the snapshot: 0.1 s
33
- placeholders for unchanged files: 0.09 s
34
- tracked paths: 0.04 s
35
36
## Rules for this loop
37
38
- **Measure quietly.** Earth runs OxygenFlow jobs, for every push to the
39
  Oxygen repositories and for metalgear. Measure when `pgrep firecracker`
40
  finds nothing if you can; otherwise run oxy and Git alternately, three
41
  times each, and record the load average. Push your commits after a
42
  measurement, not before, since each push starts jobs.
43
- **Build the bench binary** from the synced source:
44
  `rsync -a --delete --exclude target --exclude .oxy ~/development/oxygen/ claude@earth:bench/oxygen/`,
45
  then `CARGO_TARGET_DIR=~/bench/idxbin cargo build --release` there. Use
46
  `~/bench/prof-status.sh`, `~/bench/vs-git.sh` and `~/bench/linux-bench.sh`,
47
  and extend them rather than writing one-off commands.
48
- **Phase timings** (`OXY_TIMINGS=1`) name where time goes. Add phases where
49
  they are missing before optimising.
50
- **An index is derived.** Every new index or cache is keyed by what it
51
  describes, can be rebuilt from the changes at any time, and has a test
52
  build check that compares it with a full computation (as the state index,
53
  tree view and kept file order do).
54
- **Formats change freely before 1.0,** but a change format bump follows the
55
  order in loop 3's backlog (old binary commits it; then the runner and hub
56
  pins; then `make install`).
57
58
## Speed
59
60
- [ ] B0 **Baseline.** Update `~/bench/linux-bench.sh` for today's build (the
61
  state index, the manifest cache, clean and dirty status, diff, commit,
62
  log, blame, checkout, a local clone, fsck, gc, store size) with three runs
63
  each and oxy and Git alternating. Record the table in `docs/benchmarks.md`.
64
- [ ] S1 **Status and diff at Git's speed** (oxygen#41). In order, measuring
65
  after each:
66
  - the manifest as a compact binary file read without a parse per line;
67
  - the walk: compare each file's stat with the manifest without building
68
    a path string per entry (sorted walk against a sorted manifest), and
69
    skip the `.oxyignore` machinery inside tracked directories where it
70
    cannot change the answer;
71
  - no placeholder `FileState` for unchanged files (audit every user of
72
    `SnapshotResult.base_snapshot.files` first);
73
  - load the state index lazily: memory-map it and decode a file's deferred
74
    history only when that file is built;
75
  - one pass for status: the manifest check and the snapshot walk share
76
    their stats.
77
- [ ] S2 **Commit at Git's speed.** A commit extends the base it already
78
  loaded: write the new state index from the old one plus the change, rather
79
  than loading history again, and do not render what the snapshot rendered.
80
  Target: one file under 0.5 s, 1 000 files under 0.6 s.
81
- [ ] S3 **The change index: log in milliseconds.** Per state, the changes in
82
  topological order with their generation numbers and where each change's
83
  metadata is, built from the parent state's index plus the new change.
84
  `oxy log -n 100` reads 100 entries. Target: under 0.05 s.
85
- [ ] S4 **The node index: blame and file history.** Per node, the changes
86
  that touch it, so blame and `oxy log FILE` cost that file's history.
87
  Target: blame MAINTAINERS at or under Git.
88
- [ ] S5 **Checkout by comparing indexes.** Compare the two states' tree
89
  indexes by rendered content hash and write only the files that differ.
90
  Target: at or under Git.
91
- [ ] S6 **fsck at or under Git**: parallel object checking and a cheaper
92
  state pass.
93
- [ ] S7 **The first commit ahead of Git, under 2 GB**: stream reading,
94
  hashing and storing a batch of files at a time, so the whole tree's text
95
  is never in memory at once.
96
97
## Space
98
99
- [ ] P1 **Store at or under Git after gc** (324 MB against 295 MB): measure
100
  what takes the space, then try a trained zstd dictionary per repository
101
  and packing similar objects together.
102
103
## When a speed item is blocked: the other planned work
104
105
Andy's choice (2026-09-30): if the loop is stuck on the speed items (no
106
idea left that measures better, or blocked on something only Andy can
107
decide), it notes why in the log and takes the next item below instead of
108
stopping. Each follows the same rules: an issue, tests, the gate, push,
109
deploy where it applies, and a log line. Skip an item that needs Andy (a
110
decision, an account, hardware) and say so in the log.
111
112
1. **Web workspaces (P5), "VS Code in the hub"**, in parts:
113
   - [ ] P5a **flow-casfs**: a read-only FUSE mount of a state from its
114
     content-addressed chunks, in oxygenflow, measured (mount time, first
115
     read, a full walk of the Linux tip).
116
   - [ ] P5b **Open in Workspace** on a change or bookmark page of the hub:
117
     openvscode-server (MIT, unmodified) with Oxygen VCS inside a
118
     Firecracker microVM per workspace, the state mounted read-only through
119
     casfs with an ephemeral overlay for edits, and commits going back
120
     through oxy as the signed-in user. The runner hosts it (the image under
121
     `~/flow`, a workspace job kind); the hub starts it, proxies it to the
122
     signed-in user only, and stops it when idle. Boot time measured, aiming
123
     under 100 ms for the mount. Write the design into the hub and
124
     oxygenflow specs first. A fork of VS Code only if an extension cannot
125
     do what is needed, decided with Andy.
126
2. - [ ] **oxy on projects coming from Git**: say when a folder holding
127
   `.git` is skipped (oxygen#43), and honour `.gitignore` or offer to import
128
   it (oxygen#44).
129
3. - [ ] **Device sign-in** for apps and `oh` (oxygenhub#67): approve a code on
130
   the web with password and 2FA, and the app receives a scoped token. The
131
   Android client needs it.
132
4. - [ ] **An Android build image** for OxygenFlow (oxygenflow#19): JDK,
133
   Android SDK and NDK, and a Gradle cache warmed offline.
134
5. - [ ] **OxygenHub VCS**: declare its authentication provider in the
135
   manifest (oxygenhub-vscode#4), released as the next patch (see the
136
   Marketplace notes: never reuse a version).
137
6. - [ ] **Import at scale**: finish oxygen#25 (per-commit import cost), then
138
   backlog 3's H3 (Linux history slices of 2 000, 10 000 and 50 000
139
   commits, verified) and H4 (vscode's full history, about 130 000
140
   commits, into a scratch repository that is never published).
141
7. - [ ] **The hub's open issues**: runner management (oxygenhub#41, backlog
142
   2's H12 parts), a pinned subrepo left out of a Flow job for lack of
143
   access (#56), faster CI (#29), required checks over the API (#20).
144
8. - [ ] **The hub's plan** (`oxygenhub/docs/plan.md`): notifications for
145
   review requests, mentions and landings; the organisation webhooks page.
146
   Email verification and password reset need SMTP on Earth, and passkeys
147
   are for 1.0: skip both unless Andy says otherwise.
148
9. - [ ] **Housekeeping**: tick plan items that are already done (for
149
   example `oxy seal --proposal` exists), and CHANGELOG files for oxygen,
150
   oxygenhub and oxygenflow like the extensions' (backlog 2's V2).
151
152
## Also
153
154
- [ ] R1 **Rebase into the working copy** (oxygen#42, Andy's choice for the
155
  overnight loop): when `oxy rebase CHANGE --onto TARGET` would be
156
  conflicted, offer to leave the conflict in the working copy to resolve and
157
  commit, as `merge` does, rather than refusing.
158
- [ ] Z1 **Closing summary.** Re-run the full benchmark and summarise, for
159
  Andy, where oxy matches or beats Git on the Linux tree, and where it does
160
  not and why.
161
162
## Log
163
164
- 2026-09-30 Backlog written from the day's measurements (state index,
165
  changed-only builds and the manifest cache already in).