step 21e werkdock moved to own repo (#15)
* refactor: werkdock/ verlässt dieses Repository Die neun Commits unterhalb von werkdock/ sind per `git subtree split` historieerhaltend nach https://git.javagil.de/mi/werkdock gehoben; hier bleibt nichts davon zurück. Mit dem Verzeichnis geht die Build-Definition `werkdock`: Sie beschrieb ein Go-Modul, das der Kotlin-Build um sie herum nicht berühren kann — jeder Werkator-Branch baute es dennoch als `<branch>@werkdock` mit. Drüben ist sie die einzige und heißt `default`. Die Kopplung bleibt, wie Sitzung C sie gemacht hat: Werkator ruft das `werkdock`-Binary über PATH (`bwrap.werkdock`, weiterhin gepinnt), so wie es `git` ruft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(remote): das werkdock-Binary kommt aus einem eigenen Checkout Bisher baute das Skript es aus dem Unterverzeichnis. Jetzt nennt WERKDOCK_REPO den Checkout (Vorgabe: ein Geschwister dieses Repositories — die übliche Ablage, wenn man an beidem arbeitet), WERKDOCK_BINARY das gebaute Binary darin; beides ist wie jeder Transportwert aus der Umgebung übersteuerbar. Fehlt der Checkout, nennt die Meldung die Klon-URL, statt bloß „file not found" zu sagen: Das Skript kann die Lage nicht mehr selbst beheben, also sagt es, was sie beheben würde. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: Sitzung E — Werkdock hat ein eigenes Repository Plan-Schritt 21 bekommt die Sitzung, die die Herauslösung beschreibt, samt Abnahmekriterium; Plan-Index und Architektur-Skill sagen nicht mehr, sie stehe noch bevor, und der Deployment-Leitfaden verlinkt das Repository statt eines Verzeichnisses, das es hier nicht mehr gibt. Dazu das PR-Dokument nach Hausregel (docs/prs/README.md). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(remote): repo-add wendet das Instanz-Fragment an `repo-add` rief `werkator init` ohne `--apply`, `repo-init` dagegen mit. Folge: Ein so aufgenommenes Repository bekam die Sandbox-Politik nicht — `bwrap.rootfs` und `bwrap.werkdock` fehlten, und der erste Build lief auf dem nackten Host statt in der Sandbox. Gefunden beim Aufnehmen von Werkdock: `gofmt: command not found`, weil die Go-Toolchain nur im Sandbox-Image liegt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(remote): repo-add erkennt einen ~/-Registry-Eintrag, und der Kommentar sagt die Wahrheit Die Registry-Prüfung suchte nur den absoluten Pfad und meldete deshalb „not registered yet“, obwohl der Eintrag als `path: ~/werkdock` dasteht — eine Einladung, ihn ein zweites Mal einzutragen. Gegriffen wird jetzt lokal, damit beide Schreibweisen ohne zweite Schicht Remote-Quoting treffbar sind. Dazu der Kommentar über dem Laden der Env-Datei: Er behauptete, die ausdrückliche Umgebung gewinne. `set -a; source` weist unbedingt zu — die Datei gewinnt. Beim Nachziehen des Werkdock-Fragments hat mich genau das eine Runde gekostet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
06f4052848
commit
ac53b5f211
+1
-1
@@ -319,7 +319,7 @@ See [configuration.md](configuration.md) for all `server.nginx.*` keys.
|
||||
## Hostsharing Managed Webspace
|
||||
|
||||
The third deployment variant (plan step 21, verified live on a real webspace): no root, no Docker daemon, no own reverse proxy.
|
||||
Werkator runs as a systemd *user* service on the assigned localhost port ("eigener Serverdienst"), the platform's managed Apache terminates TLS and proxies via `.htaccess`, and builds run in the bubblewrap sandbox executed by the [werkdock](../werkdock/README.md) CLI (ADR 0008, step 21 session C).
|
||||
Werkator runs as a systemd *user* service on the assigned localhost port ("eigener Serverdienst"), the platform's managed Apache terminates TLS and proxies via `.htaccess`, and builds run in the bubblewrap sandbox executed by the [werkdock](https://git.javagil.de/mi/werkdock) CLI (ADR 0008, step 21 session C).
|
||||
|
||||
Werkator is never built on the webspace: the runtime bundle and the werkdock binary are built locally and uploaded (ADR 0006).
|
||||
All steps are driven by `tools/remote`; commands name their role — `instance-*` manages the installed Werkator, `repo-*` the repository it watches.
|
||||
|
||||
@@ -85,6 +85,17 @@ Bring intent 1 to the webspace: build locally, install the bundle — Werkator n
|
||||
Session D's replacement must name the role in every command and in the script's vocabulary (e.g. `instance install`/`instance update` vs `repo build`), and prefer delegating built-side operations to the `werkator` CLI instead of reimplementing them.
|
||||
- `docs/deployment.md` gains "Hostsharing Managed Webspace" as the third deployment variant — step 17 required this to be written from a verified setup, and the branch's live run provides exactly that.
|
||||
|
||||
### E — Werkdock moves to its own repository (2026-09-03)
|
||||
|
||||
Sessions B–D left Werkdock self-contained by design ("no imports from Werkator code, no Gradle coupling"), and session C reduced the coupling to a binary on the `PATH`.
|
||||
What remained was the directory move the plan promised from the start.
|
||||
|
||||
- The nine commits below `werkdock/` are lifted with `git subtree split -P werkdock`, so the history survives the move; the paths lose the prefix.
|
||||
- The build definition `werkdock` leaves this repository's `.werkator.yml` and becomes the `default` build of the new repository's own `.werkator.yml` — the same commands, minus the `cd werkdock` prefix.
|
||||
- `tools/remote` no longer builds the binary from a subdirectory: `WERKDOCK_REPO` names the checkout (default: a sibling of this repository), `WERKDOCK_BINARY` the built binary within it, and a missing checkout fails loudly with the clone URL instead of a bare "file not found".
|
||||
- Werkator's own configuration is untouched: `bwrap.werkdock` still names the executing binary and is still pinned — a branch must not substitute it (AGENTS.md).
|
||||
- The instance registers the new repository like any other (`tools/remote werkator repo-add`), so Werkdock is built and tested by the same Werkator that runs on its binary.
|
||||
|
||||
## Session Notes
|
||||
|
||||
- 2026-09-01: The fat build image exists and is live on mih34: `tools/build-bwrap-rootfs.sh` gained `--pkgs-extra`, the archive `werkator-buildenv-trixie-java-go-node.tar.zst` (515 MB, JDK 21 + Go + Node/npm) was built locally, uploaded checksum-verified, and the machine config switched to it (deduplicating nine identical bwrap blocks the install prototype had appended).
|
||||
@@ -103,3 +114,4 @@ Bring intent 1 to the webspace: build locally, install the bundle — Werkator n
|
||||
- Session B: the `werkdock/` subdirectory holds a self-contained tool in which `werkdock doctor`, an image build, and `werkdock run` work on a Managed Webspace without any Werkator involvement.
|
||||
- Session C: `./gradlew build` green with `BwrapBuildRunner` delegating to `werkdock`; the pinned-key tests and the metadata-masking tests unchanged and green.
|
||||
- Session D: a fresh Managed Webspace reaches a running, HTTPS-reachable Werkator via `tools/remote werkator install` + `start` without ever compiling on the target; `docs/deployment.md` documents it.
|
||||
- Session E: `werkdock/` is gone from this repository, the new repository builds and tests green on its own, `tools/remote` installs the binary from the sibling checkout, and the instance watches both repositories.
|
||||
|
||||
+2
-2
@@ -93,7 +93,7 @@ Added for running Werkator on Hostsharing Managed Webspaces (2026-08-10):
|
||||
|
||||
Added to correct the bwrap prototype's drift toward self-building on the webspace (2026-09-01):
|
||||
|
||||
- [ ] `21-werkdock-extraction-and-webspace-install.md` — roadmap in four sessions: close step 17's open ends, grow the sandbox tooling into **Werkdock** (a docker-like filesystem-only sandbox CLI, developed in the `werkdock/` subdirectory, later its own repository), let Werkator consume it, and replace the webspace self-build with the local-build-plus-install path of ADR 0006
|
||||
- [ ] `21-werkdock-extraction-and-webspace-install.md` — roadmap in four sessions: close step 17's open ends, grow the sandbox tooling into **Werkdock** (a docker-like filesystem-only sandbox CLI, developed in the `werkdock/` subdirectory, extracted into [its own repository](https://git.javagil.de/mi/werkdock) in session E), let Werkator consume it, and replace the webspace self-build with the local-build-plus-install path of ADR 0006
|
||||
|
||||
Added after step 21 session D exposed that `tools/remote` re-implements configuration Werkator owns (2026-09-01):
|
||||
|
||||
@@ -113,5 +113,5 @@ Step 17 depends on 11, 15, and 16, and starts with a hard precondition check on
|
||||
Step 18 depends on nothing in code but on the watched repository having migrated — its precondition check is a hard gate, not a formality.
|
||||
Step 19 depends on nothing; `WatcherState` and `/api/watcher` already carry everything it needs to render.
|
||||
Step 20 depends on nothing; the duration is already recorded, and the trend is derived read-only from `repository.history()`.
|
||||
Step 21 depends on 17; its sessions B and C grow Werkdock in the `werkdock/` subdirectory (later its own repository), and session D supersedes the self-build prototype in `tools/remote`.
|
||||
Step 21 depends on 17; its sessions B and C grow Werkdock in the `werkdock/` subdirectory, session D supersedes the self-build prototype in `tools/remote`, and session E moves Werkdock into its own repository.
|
||||
Step 23 depends on 21 session D; its per-instance file convention (transport env + init fragment) also feeds step 22's instance setup and should land before Werkbaum rolls out.
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
> **WARNING:** This document describes only the change applied in this PR.
|
||||
> It may already be outdated once the next PR is merged.
|
||||
> Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.
|
||||
|
||||
## The Problem
|
||||
|
||||
Werkdock was grown inside this repository on purpose — plan step 21, sessions B and C — and the plan said from the first line that it "moves to its own repository later".
|
||||
Everything that move needs has been true since session C: the tool has no imports from Werkator code, no Gradle coupling, and Werkator reaches it the way it reaches `git` — as a binary on the `PATH`, named by the pinned key `bwrap.werkdock`.
|
||||
|
||||
What kept it here was three references, not a dependency:
|
||||
`.werkator.yml` carried a second build definition for a Go module that has nothing to do with the Kotlin build around it,
|
||||
`tools/remote` built the binary out of the subdirectory,
|
||||
and the documentation described a directory that was about to stop existing.
|
||||
|
||||
The instance makes the cost visible: every Werkator branch built a `<branch>@werkdock` artifact, so Werkdock was rebuilt for changes that could not possibly affect it, and its own history was invisible under Werkator's branch names.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Changing Werkdock itself: the extracted repository holds the same nine commits, byte for byte, only without the path prefix.
|
||||
- Changing how Werkator uses Werkdock: `bwrap.enabled`, `bwrap.rootfs` and `bwrap.werkdock` stay as they are, still pinned, still resolved via `PATH` at run time.
|
||||
- Publishing releases of the binary: `tools/remote` keeps installing the locally built one (ADR 0006 — never built on the target).
|
||||
- Registering the new repository on the instance: that is one `tools/remote werkator repo-add` plus a registry entry, done in the rollout, not in this branch.
|
||||
|
||||
## The Solution
|
||||
|
||||
**The history moves with the files.**
|
||||
`git subtree split -P werkdock` lifts the nine commits that touched the subdirectory into a root-level history; the new repository starts from that, so `git log` and `git blame` keep working across the move.
|
||||
A plain copy would have made this PR cheaper and the tool's past unreadable.
|
||||
|
||||
**The build definition follows, and becomes the only one.**
|
||||
What was `builds.werkdock` here is `builds.default` in the new repository — same commands, minus the `cd werkdock` prefix, same `gofmt`-twice idiom (the first call names the unformatted files, the second fails the build on them).
|
||||
This repository's `.werkator.yml` is back to one definition, and a Werkator branch no longer rebuilds a Go module it cannot influence.
|
||||
|
||||
**`tools/remote` asks for a checkout instead of a subdirectory.**
|
||||
`WERKDOCK_REPO` names it (default: a sibling of this repository — the usual layout when you work on both), `WERKDOCK_BINARY` the built binary within it, and both are overridable from the environment like every other transport value.
|
||||
A missing checkout now fails with the clone URL in the message rather than a bare "file not found": the script cannot fix the situation itself any more, so it says what would.
|
||||
|
||||
**The documentation stops describing a subdirectory.**
|
||||
`docs/deployment.md` links the repository instead of `../werkdock/README.md`, the plan index and the architecture skill say the extraction happened, and plan step 21 gains session E with what was decided and what it left alone.
|
||||
|
||||
## Verification
|
||||
|
||||
- `./gradlew ktlintFormat build` green in this repository without `werkdock/`.
|
||||
- The extracted repository builds and tests green on its own — `gofmt`, `go vet`, `go test ./...` (four packages), `go build` — which is the acceptance criterion the plan set for a self-contained tool.
|
||||
- `bash -n tools/remote`, and the sibling-checkout default resolved against a real checkout.
|
||||
|
||||
## Open Questions
|
||||
|
||||
**A branch cannot remove a build definition — only add or override one.**
|
||||
Observed on this very branch: the instance built `21e-werkdock-own-repo@werkdock` and it failed, although the branch's committed `.werkator.yml` no longer defines `werkdock`.
|
||||
The cause is not a bug in the watcher — it reads the branch layer, and no fallback warning was logged — but the merge itself:
|
||||
`withBranchLayer` does `deepMerge(loadRaw(workingDir), stripPinned(branchLayer))`, so a definition present in the project layer and absent on the branch survives the merge.
|
||||
`AGENTS.md` and the architecture skill describe the branch layer as winning "including the whole `builds` section", which reads as replacement.
|
||||
|
||||
The mismatch resolves itself for this branch on merge — main then no longer carries the definition — so it does not block this PR.
|
||||
It is a decision, not an oversight to fix in passing: either `builds` is replaced as a whole (then a branch can retire a build, and a branch that only adds one must repeat the others), or the merge stays and the two documents are corrected to say that removal is not expressible on a branch.
|
||||
Reference in New Issue
Block a user