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:
Michael Hönnig
2026-09-03 15:15:15 +02:00
committed by GitHub
co-authored by Claude Opus 5
parent 06f4052848
commit ac53b5f211
27 changed files with 100 additions and 2105 deletions
+1 -1
View File
@@ -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 BD 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
View File
@@ -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.