Before retiring the ocx release, the maintainer asked for "some comfort
that i can import projects and reliably serve development back to git with
ocx2" (the forum, 2026-10-07). These slices come from the route to trunk
parity that the later reset writes out, and keep its numbers. They are
built first because the cutover waits on them
(slices-parity.md, "Milestone: the ocx release
retired"). Each says what it replaces at the trunk tip
(1f0ac30c5b), and
each is written as slices.md writes a slice.
What was found first (f3bb7b2032):
- Nothing kept the export current.
trunk's daemon ranfossil git exportonce a minute (ticket 34173149fd). Theocxrelease and slice 5 only serve the export it wrote, though both said a hook made it. Since the daemon stopped, on 2026-09-21 at 15:06 UTC, the served export has missed every check-in: theocxandocx2branches are not in it. - A plain round trip rewrites every commit.
fossil import --gitfollowed byfossil git export(Fossil 2.27) keeps each tree, but it names authors by their email, moves times by a second, drops zones, adds aFossilOrigin-Name:line and a strayunknownbranch. A clone of the upstream cannot take the work as a fast-forward. - Seeding fixes it. Seed the export's state, its
.mirror_statetable mapping each check-in to a git commit, from the import's marks, astrunk's mirror sync came to (ticket 3075dfdc01). The upstream's commit ids are then kept, a Fossil check-in exports as a commit whose parent is the upstream's own, and a clone of the upstream fast-forwards to it. Annotated tags still come back lightweight, so an import leaves tags to git: it takes the branches into Fossil, and the export keeps the upstream's tags as they are, which Fossil's export does not touch.
Slice 40: the export kept current
- Input: none: the served repository's export, where its
last-git-export-reposetting says. - Who: setup (
s), from the command line on the served host, the web page, and the hook, as the server's own process. Withheld from MCP: a unit's sandbox has no served repository. - What it does: runs
fossil git exportinto the export Fossil keeps, one run at a time. A run asked for while another holds the export's lock leaves a mark asking that run to export again; the holder exports until no mark is left. The mark is left before the lock is tried, so a run about to let go sees it, no receipt is missed and none waits on another. A mark left by a run that was killed is taken by the next. The run is kept in the export's.git: when it began, how long it took, what Fossil added, or why it failed. It sets nothing: an autopush the export has is Fossil's to do. - The hook runs it after every receipt, after its work and its wakes, and its log line holds the run.
- Output: the run, and where the export stands, as
fossil git statussays: where it is, when Fossil last exported, how many check-ins await it, its autopush and its main branch, with the last run. A dry run shows the same without exporting, so the page's card says what awaits; a failed export refuses, saying what Fossil said. - Replaces:
trunk'smirror-syncand its daemon'spoll_git_exports(src/mirror_sync.cr,src/task_worker.cr), without the clock (HISTORY.md decision 23). - Not copied: a push by OCX's own code to forgejo. A push is the
export's autopush, which
fossil git export --autopushsets; whether OCX sets it is the maintainer's to decide. - Needs first: slices 5 and 10.
- Built:
exportand the hook's run of it (spec/ocx/export_spec.cr).
Slice 39: import a git repository
- Input: the upstream's URL (https, or a path on the served host); the new repository's name; optionally the upstream branch Fossil's export treats as its main branch, else the upstream's own.
- Who: setup, from the command line on the served host and the web page, the import running as a job (slice 12's pattern) since it may take minutes; withheld from MCP.
- What it does:
- clones the upstream bare, writes its branches alone as git's
fast-export with marks, so each check-in keeps its branch (docs/fossil.md,
"Git export and import"), the upstream's own named
trunk, so a checkout opens on it, and imports it withfossil import --git, keeping Fossil's marks, all in a sandbox, since the upstream is anyone's; - places the repository beside the served one, under the name given;
- makes its export of the bare clone, its state seeded from the two marks files and the newest check-in's day; the upstream's tags stay as they are;
- then onboards it as far as slice 37 is built: the hook, where this release's is on the served repository. Its administrator sets its public URL, which the answer gives, since OCX writes no repository's config (precept C2; HISTORY.md decision 25).
- A run that fails leaves nothing behind. The same name again finishes an import cut off, the repository's own record of its import saying where it stopped, and otherwise is refused, as slice 1's create is.
- clones the upstream bare, writes its branches alone as git's
fast-export with marks, so each check-in keeps its branch (docs/fossil.md,
"Git export and import"), the upstream's own named
- Refresh: the same tool given an imported repository's name brings
in what the upstream added since, with the marks the export keeps: onto
each branch the repository has not moved past, and onto
upstream/BRANCHwhere Fossil's work and the upstream's have diverged, for a person or a unit to merge. - Output: the repository, its check-ins, its export and its main branch.
- Replaces:
trunk'simport-project URL [--archive],import-refresh NAMEand the web import page (src/agent_tool.cr,src/import_deploy.cr). Not copied: importing a Fossil repository, which is a clone;--archive, until a repository's role is wanted. - Needs first: slices 37 and 40.
- Built:
import UPSTREAM NAME [--mirrors DIR](spec/ocx/import_spec.cr), which joins the served repository's login group as slice 37 has it (the maintainer, 2026-10-08). Not yet: refresh; the web page's import as a job, so its form now runs in the request; slice 37's menu link.
Slice 37: onboard a repository
- Input: the repository, beside the served one.
- Who: setup, as slice 39 does it, or from the command line on the served host for a repository made otherwise.
- What it does: installs the hook (slice 10); sets the repository's
email-urlfrom the served one's, so a unit's workspace clones it; lets the person onboarding sign in there with their own password, by Fossil's login group with the served repository; and links the web page in its menu. - Replaces:
trunk'sRepoBootstrap.onboard. Not copied: its session poll (decision 23), its seeded secrets and provider settings (precepts C2 and C6), its chat runner (the/chatslice), its ticket fields (decisions 32 and 33) and its skin. - Needs first: slice 10.
Slice 36, many repositories on one host, needs no code of its own here: there is no daemon to fan out, each repository has its own hook, units are laid out per project, and the page is served for every repository Fossil serves. Slice 39's second repository shows it.
Milestone: the git round trip
Shown on a scratch served repository, as each slice is: a git repository imported; a unit's check-in on it; a clone of the upstream fetching that check-in from the export as a fast-forward; an export killed partway through and completed by the next receipt; an import that fails leaving nothing. With it, and the maintainer's answer on whether "back to git" also means a push to the upstream's host, the cutover's lists are whole.
Shown, 2026-10-07 (614d448140):
GitHub's octocat/Hello-World imported beside a scratch served repository;
a unit's check-in made with run in its sandbox; the hook's run after its
push exporting it; a plain clone of the upstream fetching it through the
release's git program as a fast-forward onto the upstream's master; an
import that could not clone leaving nothing; and, for slice 40, an export
killed partway through 2000 check-ins completed by the next run.