- [x] Tests: unit tests per module and an end-to-end test that pushes with a real `oxy-core` client and fetches every page.
16
- [x] Oxygen changes it needed (in the Oxygen plan, phase 4): bare repositories, embeddable server, unbound repositories, adoption of anonymous changes by seals, `oxy seal`.
17
- [ ] Developer edition running on Earth with `oxygen`, `oxygen-vscode` and `oxygenhub` hosted (docs/deploy.md).
- [x] Passwords (Argon2id), signed session cookie bound to a per-account salt, CSRF tokens on every form, same-origin check on every non-GET request, TOTP with recovery codes, sign out everywhere.
23
- [x] Registration modes (open, invite, closed; first account is the administrator), invitations, admin page (accounts, ban, promote, registration mode, audit log).
24
- [x] Roles: owner and site admin → admin; organisation owners → admin, members → the organisation's default role; collaborators (accounts and teams) → their role; visibility public/internal/private decides the anonymous and signed-in floor. A repository the viewer may not read is a 404 everywhere, including the protocol.
25
- [x] Personal access tokens: hashed, scoped (`repo:read`, `repo:write`, `repo:admin`, `user:read`), optionally limited to repositories, with expiry; the protocol checks role and scope; site tokens from `hub.toml` remain for bootstrapping.
26
- [x] Linked identities: upload `oxy identity export`, sign the challenge with `oxy identity sign-challenge`, verified with `verify_challenge`; authors whose key is linked show as accounts on history, change and compare pages.
-State caching (spec §16.3): `repos::cache::StateCache`, a bounded LRU of loaded states keyed by repository id and heads, shared across threads since `State` became `Send + Sync`. Measured on the `oxygen` repository (90 changes): overview 154 ms cold and under 2 ms warm, history 25 ms, tree under 1 ms. Rendered-page and syntax-highlight caches are still to do.
<<<<<<< oxy conflict 1 of 1, side 1 of 2: deleted by change 138969c8 "State cache keyed by heads; history and graph through oxy-core's lanes and log window"
41
-------
42
-`State` holds `Rc` values, so a cross-thread cache needs a `Send` snapshot type in `oxy-core` first.
43
======= oxy conflict 1 of 1, side 2 of 2: change a8a6b660 "Push log records states, heads and change counts from the push report"
44
45
The cross-product order of work is in `oxygen/docs/roadmap.md`.