OXYGENHUB

Changelog per change: a check in the gate, and Unreleased caught up e4595038502a

From now on a commit that changes code adds a line under ## Unreleased
(scripts/changelog-check.sh, run in the gate; NO_CHANGELOG=1 for changes
users won't notice), and versions change only at release. Unreleased now
lists everything since the last release.
Author
Andy McCall @andymccall <[email protected]>
via
agent agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key 7dcf1e9e7256
When
· 2026-10-19 20:16 UTC
Signature
◈ sealed by agent:claude@andymccall
Hash
e4595038502a2a70b39cedbd575a9282e6ee2a50bc147b094f8f35d8519fa6d6
Depends on
25c6adfaa559 648724d8e0de 68dcf21fe055 8fd78eb52ad2 d02e545dc265 f4324e406906
Depended on by
ed931d1d1102 045340293dc7 a42f9fb47e37 0588de69a84d 569802ebae0e 642da2636de2 7f617ee9b3ad 4275ecb110f5 fa53a2849de8 78b49d4d01f0 7a3cc5149a14 c0d4075cadc0 b5e98094eb8f 642fa213de80 80b069facc69 2452b4407ab7 4afe288b7946 9bd98cfb4f7e e02edccce98c 795b8b502ded 544d0541a7e5 ff6987682725 c8d9059e4e70 157d02e95586 4476cdbb0443 570e35310f31 b260109d27c5 7bd805ffb418 d3b270909c78 45a6f5ec85cf f0ef9778e587 82202a4d0025 ee130dd9eef2 1ec6fdbc6bcb 6f06d9f912b4 2b95bc24d7d6 771661aa50f4 27825564bc16 8156967b882c ef7d4ea6f33b
In bookmarks
identical-sides keyless-tags main push-notes subrepo-pin-state
In tags
v0.10.0 v0.11.0 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
Edits
3 atoms, 1 tree operation, 3 files

Browse the tree at this change

added scripts/changelog-check.sh +27 −0
1 +
#!/bin/sh
2 +
# The changelog check (2026-10-19): a commit that changes what users get
3 +
# adds a line under "## Unreleased" in CHANGELOG.md, so a release's notes
4 +
# are written as the work is done and versions say what changed.
5 +
#
6 +
#   scripts/changelog-check.sh [PATH...]
7 +
#
8 +
# PATHs are what the commit will take (as given to `oxy commit`); without
9 +
# any, the working copy's changes. Code is anything under src/, crates/,
10 +
# templates/, assets/, packaging/, images/ or scripts/, except tests.
11 +
# Docs, pipelines, pins (deps/) and lock files need no line. For a code
12 +
# change users won't notice (a refactor, a test helper), set NO_CHANGELOG=1.
13 +
set -eu
14 +
[ "${NO_CHANGELOG:-}" = 1 ] && exit 0
15 +
cd "$(dirname "$0")/.."
16 +
if [ "$#" -gt 0 ]; then
17 +
    paths=$(printf '%s\n' "$@")
18 +
else
19 +
    paths=$(oxy --plain status --json | python3 -c 'import json,sys; print("\n".join(p["path"] for p in json.load(sys.stdin)["paths"]))')
20 +
fi
21 +
code=$(printf '%s\n' "$paths" | grep -E '^(src|crates|templates|assets|packaging|images|scripts)/' | grep -vE '(^|/)tests?/|_test\.rs$' || true)
22 +
[ -z "$code" ] && exit 0
23 +
printf '%s\n' "$paths" | grep -qx 'CHANGELOG.md' && exit 0
24 +
echo "changelog: these changes touch code but CHANGELOG.md has no new line under ## Unreleased:" >&2
25 +
printf '%s\n' "$code" | sed 's/^/  /' >&2
26 +
echo "add one (Added / Changed / Fixed / Security, with the issue number), or set NO_CHANGELOG=1 if users won't notice" >&2
27 +
exit 1
modified CHANGELOG.md +30 −0
1 1
# Changelog
2 2
3 +
## Unreleased
4 +
5 +
- **Fetch checks the hub's transparency log (oxygenhub#238).** A hub that keeps a log sends its latest checkpoint with every refs answer, and each bookmark's attestation with its log entry and inclusion proof. The first fetch pins the hub's log key in `<oxy home>/tlog/<hub>` with the last checkpoint seen. A later checkpoint must be signed by that key and extend the last one: a smaller log, another root at the same size or a failed consistency proof fails the fetch, saying the hub showed two histories. An attestation not logged yet, or not proved, is only a note for now, printed by `fetch` and `pull` and in `--json`. A hub that comes back with a new log key (a new key, a reused address, a rename) is a loud note, and the new key is pinned. Older hubs and clients ignore the new fields.
6 +
7 +
- **`oxy tlog verify` audits a hub's whole log (oxygenhub#238).** It accepts the hub's checkpoint by the same rules as fetch, downloads every entry and requires them to make the root the checkpoint signs, then lists this repository's entries, a key's (`--key`) or all of them (`--all`); `--json` too. It also shows which witnesses cosigned and when.
8 +
9 +
- **Trusted time from witnesses (oxygenhub#240).** An entry's integrated time is the earliest time a trusted witness cosigned a checkpoint that holds it, by the witness's clock, so a hub can only make it later, never earlier. A fetch pins the hub's witnesses beside its log key (`<oxy home>/tlog/<hub>.witnesses`; a new or changed witness key is a note), counts a cosignature only when it verifies against a pinned key, and checks a delegate's delegation and a short-lived key's certificate at that time. Without one it checks them as before, at the hub's acceptance or the attestation's own time. A claimed time more than 10 minutes off the integrated time is noted, not refused, for now. The wire change is additive.
10 +
11 +
- **`oxy witness serve`: a witness anyone can run (oxygenhub#238).** `oxy witness serve --name HOST --log ORIGIN=FILE …` serves the C2SP tlog-witness `add-checkpoint` call. It cosigns, with this oxy home's key and its own clock, each checkpoint that verifies with the log's key and extends the last one it cosigned, and refuses a fork. What it cosigned is kept per log in `--state`, so it survives a restart.
12 +
13 +
- **`oxy show --stat` (#119).** Lists the files a change touched instead of its diff: each path with lines added and removed and its kind, renames as from → to, and a total. `--json` gives each file's counts.
14 +
15 +
- **`oxy merge` takes a remote's bookmark (#117).** `oxy merge oxygenhub/develop` said "no bookmark": merge looked only at local bookmarks, so merging what a remote has meant switching to it, pulling and switching back. It now takes a remote's tracking bookmark as last fetched, as revsets do, and says where it looked when neither exists.
16 +
17 +
- **Commit a resolution by paths, and amend only some paths (#118).** A conflict resolution can be committed by paths, leaving other work uncommitted on top of the resolved state, as long as the paths include every file it resolves, whole; otherwise the refusal names them. `oxy amend PATH…` folds only those paths into the head and leaves the rest uncommitted.
18 +
19 +
- **`oxy doctor` checks the trust policy (#127).** A repository with no policy was "Everything looks right" while every fetch warned that nothing was verified. Doctor now has a trust line: no policy is a warning that says who sets one and how; a policy shows its serial, roots, rules and expiry, warns within 30 days of expiry and fails once it has expired.
20 +
21 +
- **The same file added on both sides is one file (#101).** The same path added on two bookmarks with identical content (files, symlinks, or subrepos at the same pin) now merges with no conflict and nothing to resolve. Every peer and the hub show it the same way whatever order the changes came in, and it stays one file through later edits, moves, removals and partial commits. Different content or a different mode is still a name conflict, and directories are not unified. The stored and signed formats are unchanged.
22 +
23 +
- **A bookmark nobody can verify no longer breaks every fetch (oxygenhub#266, oxygenhub#271).** A delegate or short-lived key that moved a bookmark without signing any of its changes left every client failing the whole fetch with "unknown key". A fetch now carries the identities and certificates of the keys that signed every bookmark's latest attestation and every tag's, so clients, older ones included, can verify the move. A client that still cannot verify a bookmark other than the current one leaves that bookmark as it was, warns naming it and why, and fetches the rest. The current bookmark (the one a pull takes or a clone checks out) still fails, as does a missing, unauthorised or rolled-back attestation. The signers are gathered once per operation, not on every fetch call: a repository in a bucket with 145 bookmarks had taken 14 s a fetch.
24 +
25 +
- **Readers never wait for a push or gc (oxygenhub#249).** A repository can now be read safely while another process writes it. A handle reads the operation head once and keeps it, so one request never mixes two views. A read that misses reloads the pack list and tries once more. A repack retires the packs and loose objects it replaces instead of deleting them, and `gc` deletes them only an hour later; `oxy gc` says what it deleted or kept for readers. A forge no longer needs to hold readers back while it pushes or collects garbage.
26 +
27 +
- **A repository kept in a bucket lists its packs less often (#116).** Every open listed the bucket's packs, and a forge opens the store once per request. The pack listing is now kept for 30 seconds and forgotten the moment this process writes or deletes a pack, so its own packs are never hidden; another writer's new pack is seen within 30 seconds. Opening a store no longer sends a request per pack, and a bucket store's stat is a HEAD of the key, not a listing. A server's `/health` counts pack listings, kept listings and other listings apart.
28 +
29 +
- **Text that looks like a conflict marker no longer blocks a resolution (#126).** A file that showed oxy's own conflict markers, such as documentation or a test fixture, could never be committed as resolved ("markers remain"). A file now still has markers only when it holds a marker line oxy wrote for its conflicts. A real marker left behind is still caught.
30 +
31 +
- **A carried switch no longer says carried files were removed (#120).** After a switch that carried the working copy's changes, oxy said new files were "removed from disk" although they were still there. Carried files are now left out of what was removed, and the switch names what it carried.
32 +
3 33
## 0.4.6 (2026-10-17)
4 34
5 35
- **A keyless agent's grant token is its only credential (oxygenhub#241).** A home holding an agent grant token and no hub token now offers the grant to that hub, which accepts it for fetch and push as an agent's token of the owner's account (writing when the grant gives `refs`). The agent pushes its own work, so its seal is its own; it needs no personal access token.
…
214 unchanged lines
modified README.md +2 −0
…
40 unchanged lines
41 41
42 42
The binary is `target/release/oxy`.
43 43
44 +
**Changelog:** a commit that changes code adds a line under `## Unreleased` in CHANGELOG.md (Added, Changed, Fixed or Security, with the issue number); versions change only at release. `scripts/changelog-check.sh [PATH...]` checks it for the paths a commit takes (the working copy's changes without any) and runs in the gate; `NO_CHANGELOG=1` for code changes users won't notice.
45 +
44 46
## Quick start
45 47
46 48
```
…
82 unchanged lines