Files
werkator/docs/werkator.werkbaum
claude-codeandClaude Opus 5.5 5e26ad1ff0 A Docker image is built from the build's own workspace, under a tag of its branch (v1.43.8)
docker.dockerfile and docker.context are branch settings, and docker build ran in the primary
checkout without checking them: a branch could send .git/werkator or the home of the service
account to the daemon and copy the tokens into its own image. Both are now refused at load time
outside the workspace, and resolved in the workspace by real path before docker build.
An image built from a Dockerfile gets Werkator's own tag per repository and branch, with one
scope for the pull-request target builds, so no branch replaces the image another build runs in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:27:34 +02:00

497 lines
22 KiB
Plaintext

%% Werkator, planned with Werkbaum (https://werkbaum.javagil.de): what exists, what was dropped, what comes next.
%% Status: [^] live on mih09 or in use, [x] merged but not in use, [~] in work, [ ] planned, [?] idea, [-] dropped.
%% Each PR updates this file; see docs/agentic-workflow.md. The block behind --- explains the nodes with an id.
%% mih09 deploys every merge to main itself, so a merged node is [^].
[~] #wk: Werkator https://git.javagil.de/mi/werkator
- [~] #exec: Build execution and executor
- [^] Async executor, worktrees, logs, cancel (L)
" Plan steps 01 and 04, v0.9.0.
" Builds run in .git/werkator/worktrees per branch.
- [^] Shutdown marks builds INTERRUPTED, recovery re-runs them (S)
" v0.9.5
- [^] "Build current head" on the Branches view (S)
" PR#3, v1.0.1
- [^] Configurable executor.buildTimeout (S)
" PR#48; default 30 minutes.
- [^] A push during a running build is not lost (S)
" PR#57
- [^] Processor time per build (M)
" PR#67, PR#68, PR#71, PR#73
" Docker builds record none: the work runs under the daemon.
- [^] Phase timing and executor.overheadBudget (M)
" PR#70, plan step 14
- [^] Cancel replaces delete for active builds (S)
" PR#95, PR#98; a cancelled queued build is recorded at once.
- [^] executor.maxConcurrentPerRepository (S)
" PR#103
- [^] Executor decisions split into classes (M)
" PR#99, PR#106, PR#108, PR#109: BuildSlots, ActiveBuilds, CommandProcess, BuildLogs.
- [^] One werkdock import per image (S)
" PR#121; new status "build environment failed".
- [^] CI=true in every build (XS)
" PR#132; part of RFC 0006 step 2.
- [ ] Ownership repair after Docker builds (S)
" Plan step 14 item 3; Docker only (vm4006).
" Needs a container test.
- [?] Cancel on a new commit instead of queue-behind (S)
" Deferred in plan step 06.
- [?] Warning when a build nears its timeout (XS)
" PR#48
- [~] #sandbox: Sandboxes: Docker, bwrap and werkdock
- [^] Docker build runtime (M)
" Plan step 11
- [^] Read-only git metadata in Docker builds (S)
" Plan step 16
- [^] Nightly Docker prune timer (S)
" PR#80 removes anonymous volumes; PR#83 keeps the build images.
- [^] bwrap user-namespace runtime for Managed Webspaces (L)
" PR#4, ADR 0008, plan step 17
- [^] Werkdock in its own repository; Werkator uses its CLI (L)
" PR#6, PR#7, PR#15, plan step 21
- [^] Config section bwrap renamed werkdock (S)
" PR#19, PR#131; the old name is read with a warning.
- [^] werkdock import verb and stale-binary rebuild (M)
" PR#50
- [^] Testcontainers over the werkdock API socket on the webspace (S)
" PR#53
- [^] One shared Gradle home: werkdock.gradleHome (S)
" PR#76
- [^] Build environments that no configuration names are removed (S)
" PR#77
- [^] docker.socket opt-in and pinned (S)
" PR#55; PR#72 made it settable per build.
- [^] docker.env host override wins; rootlesskit host override (S)
" PR#85, PR#86
- [ ] Drop the "load -i --name" fallback (XS)
" PR#50; when every werkdock has import.
- [ ] #sandbox.alias: Drop the bwrap alias (XS) :#config.step18
" PR#19; together with plan step 18.
- [?] Disposable Docker daemon per build (M)
" PR#55; audit finding 3 is half fixed.
" DinD needs a rootful host daemon.
- [?] Bind mount for credential files in Docker follow-ups (S)
" PR#23
- [?] Shared .konan directory like gradleHome (XS)
" PR#76, PR#77
- [?] MemoryMax and TasksMax on the webspace unit (XS)
" PR#4
- [?] werkdock library mode: rootfs building blocks on the HDD (L)
- [-] #sandbox.proot: proot and fakechroot
- [-] #sandbox.native: Plain native builds with hand-installed toolchains
- [-] #sandbox.levels: Werkdock RFC 0002 levels 2 and 3
- [~] #config: Configuration, build definitions and pinning
- [^] Layered YAML config: machine, project, branch (M)
" v0.9.0
- [^] Build definitions: builds, trigger, ! excludes, statusContext (L)
" ADR 0007, v0.9.14 to v0.9.20
- [^] werkator.version since and below in config files (S)
" v0.9.18
- [^] init --apply fragment layer and control-token command (M)
" PR#8, PR#9, plan step 23
- [^] init reads its config from the repository root (XS)
" PR#22
- [^] A blank credential does not shadow an inherited one (S)
" PR#51
- [^] Shape check and pinned values written back after merge (S)
" PR#55
- [^] Config checks split for Mutation-CRAP (S)
" PR#112, PR#120, PR#131
- [ ] #config.step18: Remove the legacy branches section, set FORMAT_BROKE_IN (M)
" Plan step 18, the last open plan step.
" Needs every hs.hsadmin.ng branch config free of a top-level branches key.
- [ ] #config.gittally: Remove the .gittally.yml name fallback (S) :#config.step18
" PR#1; the old name is then rejected.
- [?] Should a branch be able to remove a build definition? (S)
" PR#15
- [?] Pin docker.env too (XS)
" Security audit TODO 6.
- [?] Gradle 9 upgrade (S)
" ADR 0002; waits for openapi-generator and ktlint support.
- [-] #config.autobuild: Keep extending autoBuild
- [-] #config.parallel: autoBuild and builds in parallel forever
- [-] #config.pinbuilds: Pin the whole builds section against the branch layer
- [-] #config.maxconc: builds.maxConcurrent
- [-] #config.secrets: Mark secrets in the WerkatorConfig schema
- [~] #watch: Watcher, triggers and follow-up builds
- [^] Branch polling, atTimes schedules, startup recovery (M)
" Plan step 06
- [^] Hourly ??:MM slots; local refs fast-forwarded (S)
" v0.9.11, v0.9.16
- [^] Watcher health banner for an unreachable origin (S)
" Plan step 19
- [^] Follow-up builds: trigger.afterSuccessOf (L)
" PR#23; a deployment is a build that follows a green build.
- [^] Branch-owned sandboxed follow-ups (S)
" PR#74
- [ ] #watch.list: afterSuccessOf as a list, like needs (S)
" PR#23; the same work as part of RFC 0006 step 3.
- [~] #multi: Multi-repository instance
- [^] ADR 0009, RepoContext, registry in ~/.werkator.yml, --repo (XL)
" PR#10, PR#11, PR#12, plan step 22 A to C
- [^] Repository-scoped routes /repos/<name> and /api/repos/<name> (M)
" PR#13, plan step 22 D
- [^] Rollout on mih09 (S)
" Plan step 22 E
- [?] Round-robin fairness across repositories (S)
" FIFO was decided on 2026-09-02.
- [?] Share buildenv rootfs trees across repositories (M)
" Waits for the Werkdock image store.
- [-] #multi.federation: Federation dashboard over single-repository instances
- [-] #multi.prefix: Repository prefix on artifactKey
- [~] #pr: Pull-request builds
- [^] requirePullRequest gate: build only branches with a PR (S)
- [^] Open PR shown as PR#n, then in its own column (S)
" PR#81, PR#82
- [^] Pull-request target builds: onPullRequestTarget, fresh home, own pool (L)
" PR#117, PR#118, PR#119, PR#120, PR#122
- [^] A commit status lost on a dead connection is sent once more (XS)
" PR#155; werkcrappit PR#68 stayed pending: ai-review/gate never got its success.
- [ ] Show the pull request target in the UI and the API DTOs (S)
" PR#117
- [?] Rebuild a reopened PR with an unchanged head (XS)
" PR#117
- [?] PR targets tile only where a target definition exists (XS)
" PR#119
- [~] #ui: Web UI
- [^] Thymeleaf pages and werkator.js polling; release-notes page (M)
" Plan step 08
- [^] Kin design: IBM Plex, logo, header, imprint and privacy links (L)
" RFC 0001; PR#34, PR#35, PR#38, PR#39
- [^] Repositories page /repos, GET /api/repos, repository line (M)
" PR#37
- [^] Instance home page and switchable dark mode (L)
" PR#54, RFC 0003
- [^] Mobile nav icons; control-token feedback (S)
" PR#56, PR#47
- [^] Build-duration trend per definition (M)
" PR#49, plan step 20
- [^] "Restarting" indicator during self-deployment (XS)
" PR#75
- [^] #restart2: Two restarts per row: same commit, newest commit (M)
" PR#150; follow-ups, also those a branch defines, and pull-request targets refuse the newest commit.
" PR#151 split BuildsApiController.restart again: the nightly gate measured 15.64.
- [^] A failure overtaken by a newer run or a deleted branch is shown as outdated (S)
" PR#156; grey in the History and the home strip, the reason in the tag's title.
- [^] Builds panel on the home page: running, queued, failed; five tiles per row (S)
" PR#160; pages 1440 px wide, failures of the last week that no build of the same name answers or runs again.
- [?] Three-state theme switch: light, dark, follow browser (XS)
" PR#54
- [?] Relative timestamps on cards (S)
" PR#54
- [?] History paging or range selector (S)
" PR#59
- [?] Duration trend shows CPU time; slow-drift detection (S)
" PR#67, PR#49
- [-] #ui.rfc0001: RFC 0001 options A to F
- [-] #ui.trendbranch: Duration trend per branch
- [^] #artifacts: Artifacts and history retention
- [^] File artifact store, retentionPerBranch (M)
" Plan step 05
- [^] Age-based retentionMaxAge (S)
- [^] Permanent latest-green links (S)
- [^] History survives its branch: branchGoneAt (M)
" PR#59
- [^] Run history outlives artifacts: artifactsPrunedAt (S)
" PR#84
- [^] Markdown reports in the artifact index (S)
" PR#88, PR#90
- [^] Artifact CORS; private artifacts, builds.<name>.publicArtifacts (L)
" PR#96, PR#114
- [-] #artifacts.sqlite: SQLite instead of JSON files
- [~] #metrics: System page and metrics
- [^] Metrics page; critical utilization highlighted (M)
" Plan step 09
- [^] Quota-aware disk metrics (M)
" PR#16; PR#63: an unreadable quota is not the volume.
- [^] Health page: PSI, load, swap, three-tier history (L)
" PR#27, merged as PR#29
- [^] Multiple disks: metrics.disks (M)
" PR#33
- [^] Charts, disk breakdown dialog, physical-headroom marker (L)
" PR#40, PR#41, RFC 0002
- [^] Storage pressure sampled from /proc/pressure/io (S)
" PR#69
- [^] Swap thresholds and verdict colours (S)
" PR#100, PR#101, PR#102
- [^] Sampling and view split into steps; disk verdict judges budget and volume (M)
" PR#111, PR#116
- [^] Swap-out card with history; cards in one row (M)
" PR#146
- [^] OOM kills tile; tiles in two rows of four (S)
" PR#147
- [?] Charts for load and pressure on /system (S)
" PR#54
- [?] Fill the CPU value from history right after a restart (XS)
- [?] Feed the pressure figures into the verdict or the sizing (S)
" PR#69; needs about a month of pressure history.
- [?] Per-repository disk breakdown (S)
" RFC 0002 decision 4
- [?] Slice palette: buildenv and other differ (XS)
- [-] #metrics.a2: RFC 0002 A2: stacked bar in the disk card
- [-] #metrics.b2: RFC 0002 B2: second card
- [-] #metrics.switch: metrics.disk quota or filestore switch
- [~] #sizing: Capacity sizing
- [^] Capacity advice (M)
" PR#30, merged as PR#32
- [^] Sizing corrections and Hostsharing order mail (M)
" PR#42, PR#44
- [^] Sizing by waiting, in bookable steps (L)
" PR#58, RFC 0004
- [^] Disk sized by the level it holds; RAM downsize without the 40 % gate (S)
" PR#78, PR#79
- [^] CPU, RAM and disk advice split into steps (S)
" PR#113, PR#123
- [ ] Read oom_kill into the RAM verdict (S)
" RFC 0004, PR#58; waits for data, not for a node.
" Needs experience with the machine-wide counter.
- [ ] RAM sizing rule on swap-out (S)
" PR#102, PR#146; waits for data, not for a node.
" Needs weeks of the swapOut series, recorded since 2026-10-10.
- [?] Bookable steps from a Hostsharing API (M)
" RFC 0004 B1
- [~] #selfdeploy: Self-deployment
- [^] Static maintenance page during restarts (S)
" PR#17
- [^] RFC 0005 step 1: tools/self-deploy, staged swap, watchdog (M)
" PR#61
- [^] Adoptium toolchain: the runtime starts on the glibc of Debian 12 (S)
" PR#62
- [^] Temurin 25 in the toolchain and in the runtime bundle (S)
" PR#152, werkregie ADR 0001; Kotlin 2.4.21, Gradle stays 8.14.5.
- [^] Runtime swapped only while the service is down (S)
" PR#64
- [^] restartsInstance: the instance drains and ends itself (M)
" PR#65, PR#66, RFC 0005 step 2
- [^] Restart only from a repository with selfDeploys: true (S)
" PR#87
- [?] Self-deployment on a Docker host with a system unit (M)
" Needs a new RFC.
- [-] #selfdeploy.pathunit: Option C: systemd path unit as deployer
- [-] #selfdeploy.mainonly: runtimeBundle on main only
- [-] #selfdeploy.temurin: Temurin baked into the rootfs
- [~] #security: Security and privacy
- [^] Security audit: bindAddress 127.0.0.1, control token not in pages (M)
" v0.9.9, v0.9.10
- [^] robots.txt served by Werkator (XS)
" PR#25, merged as PR#26
- [^] Token-dependent responses never cached (S)
" PR#45
- [^] Private repositories obscured; metadata, not content (M)
" PR#43; PR#54, RFC 0003 D8
- [^] Six audit findings fixed (L)
" PR#55: CSP sandbox, symlink containment, read-only checkout, log names, socket opt-in, shape check.
- [x] Links between artifacts of a private repository (XS)
" PR#164: control-token cookie SameSite=Lax, artifacts stay sandboxed.
- [x] Build variables off the command line of werkdock and docker (S)
" PR#166: bare -e KEY, the value in the CLI's environment; werkdock PR#17 keeps it off bwrap's.
- [x] Artifact directories stay inside the build's workspace (S)
" PR#167: refused at load time and again before the copy, real path included.
- [x] Private names hidden on watcher state, System and Current pages (S)
" PR#169: RepoRouting.hidden on three more answers, RFC 0003 D8.
- [x] Docker images built in the workspace, tagged per branch (S)
" PR#168: Dockerfile and context inside the workspace by real path; tag werkator-build/<scope>.
- [?] Real UI authentication (L)
" Needs an ADR that revises ADR 0004.
- [-] #security.login: Pages behind a login
- [-] #security.robotsinit: robots.txt generated by init
- [~] #ops: Deployment and operations
- [^] init --systemd user unit (M)
" Plan step 12, ADR 0004
- [^] Managed nginx/TLS container, opt-in (L)
" Plan step 13, ADR 0005, PR#124
- [^] jlink runtime bundle (M)
" Plan step 15, ADR 0006
- [^] Rename GitTally to Werkator (L)
" PR#1, v1.0.0
- [^] tools/remote: any host layout, authenticated clone, SSH multiplexing (M)
" PR#18, PR#21, PR#24, PR#28
- [^] Unit declares SuccessExitStatus=143 (XS)
" PR#73
- [ ] Bring vm4006 from v1.37.12 to main (S)
" Needs init --systemd once; remove TESTCONTAINERS_HOST_OVERRIDE.
- [-] #ops.spa: SPA or server push
- [-] #ops.compose: External compose stack instead of managed nginx
- [-] #ops.graal: GraalVM native image
- [-] #ops.container: Containerized Werkator runtime
- [~] #forgejo: Forgejo compatibility
- [^] ADR 0010, RFC 0006, export:forgejo and tools/werkator-to-forgejo (M)
" PR#92
- [^] Export notes by topic; job as header and steps (S)
" PR#115
- [ ] RFC 0006 step 2 rest: GITHUB_* and FORGEJO_* variables in every build (S)
" PR#92
- [ ] #forgejo.s3: RFC 0006 step 3: cheap deviations, one PR each (M) :#watch.list
- [ ] #forgejo.s3b: RFC 0006 step 3b: build environments as registry images (M)
- [ ] #forgejo.s4: RFC 0006 step 4: decide the deviations that stay (S)
- [ ] #forgejo.s5: RFC 0006 step 5: Werkator reads the workflow subset (L) :#forgejo.s3,#forgejo.s3b,#forgejo.s4
- [ ] #forgejo.s6: RFC 0006 step 6: one workflow on both systems in production (M) :#forgejo.s5
- [?] Workflow as the primary format, by a new ADR (XL)
- [-] #forgejo.free: Keep the own format free
- [-] #forgejo.replace: Replace the own format by the workflow format now
- [~] #tests: Tests, mutation testing and Mutation-CRAP
- [^] Kotest, MockK, WireMock, Testcontainers (S)
" ADR 0001
- [^] Flaky tests fixed (S)
" PR#20, PR#46, PR#60, PR#97, PR#157
- [^] unitTest and integrationTest tasks by spec name (S)
" PR#91
- [^] Nightly mutation build with Mutation-CRAP (M)
" PR#93, PR#94
- [^] Target 15, red from 12, gate as a ratchet (S)
" PR#104
- [^] Mutation-CRAP campaign, gate 650 to 15 (XL)
" PR#105 to PR#131
- [^] PIT memory and faster mutation tests (M)
" PR#134 to PR#145
- [^] PIT minions on the toolchain's JVM (S)
" PR#154; since PR#152 they ran on Gradle's Java 21 and found no test.
- [^] No endless loop for a mutant in the history's gap filler (XS)
" PR#162; HistoryTier.nulls gave MEMORY_ERROR, an inconclusive gate.
- [ ] Mutation tests in every build (L)
" Incremental on branches, full on main; the speed steps are done.
" The split, seeded from the history.bin of main, is still to be designed.
- [ ] Measured heap limit for PIT minions (S)
" PR#135, PR#136
- [-] #tests.frameworks: JUnit 5 or Spek 2
- [-] #tests.executorit: BuildExecutorIntegrationTest inside PIT
- [-] #tests.xmx512: PIT minions at -Xmx512m
- [-] #tests.origin: Version check against origin/main
- [~] #process: Development process and docs
- [^] A version per PR, checked by ReleaseVersionConsistencyUnitTest (S)
" PR#52
- [^] docs/llms.md (S)
" PR#36
- [^] Agents open PRs as WIP; AI review by werkrevisor; shared agentic workflow (S)
" PR#127, PR#128, PR#148
- [^] Werkbaum plan (S)
" PR#149
- [^] Codex review by the runner of werkrevisor, advise only (XS)
" PR#153
- [x] Codex review holds the merge (XS)
" PR#158; ai-review/codex is a required status.
- [x] A misreported build status waits for the human (XS)
" PR#159: Jev category status_misreported; BuildSettingsSource is a hard path.
- [x] docs/agentic-workflow.md from the master copy of werkregie (XS)
" PR#161
- [^] The AI review skips generated sections of the docs (XS)
" PR#165, after werkrevisor PR#122.
- [?] CI check that llms.md stays in sync (XS)
" PR#36
---
#sandbox.proot
ADR 0008: proot and fakechroot are slow and fragile, and they isolate nothing.
#sandbox.native
ADR 0008: native builds with hand-installed toolchains give no isolation.
#sandbox.levels
Level 2 pulls OCI images, level 3 offers a daemon API.
Deferred indefinitely on 2026-09-01; see plan step 21.
#sandbox.alias
The alias bwrap goes with plan step 18, which sets ConfigVersions.FORMAT_BROKE_IN.
#config.step18
The legacy branches section is read only while no build is defined.
When it is removed, FORMAT_BROKE_IN is set, and a leftover branches key is rejected by name.
#config.gittally
The fallback to the old name rides on plan step 18, like the bwrap alias.
#config.autobuild
ADR 0007: an autoBuild slot is a job in disguise.
#config.parallel
ADR 0007: autoBuild and builds in parallel forever are two ways to say one thing.
#config.pinbuilds
Reverted on 2026-08-29: a branch must describe its own CI (ADR 0007).
#config.maxconc
ADR 0007: the key moved to executor.maxConcurrent, without an alias.
#config.secrets
PR#51: too much machinery for two keys.
#watch.list
The list form is the counterpart of needs in a workflow; it is part of RFC 0006 step 3.
#multi.federation
ADR 0009: a dashboard over single-repository instances keeps N services and N ports.
#multi.prefix
Plan step 22: not needed, and it renames existing directories.
#ui.rfc0001
Option G, "Kin", replaced the options A to F.
#ui.trendbranch
Plan step 20 was revised to one trend per build definition.
#restart2
One restart repeats the build at the same commit, the other builds the newest commit of the branch.
A follow-up build and a pull-request target build run at a given commit, so they refuse the newest commit.
#artifacts.sqlite
ADR 0004: not needed; the repository interface keeps the switch possible.
#metrics.a2
RFC 0002: the cards may not grow.
#metrics.b2
RFC 0002: a second card doubles the cards.
#metrics.switch
PR#16: a choice that nobody makes.
#selfdeploy.pathunit
RFC 0005: not needed once restartsInstance exists.
#selfdeploy.mainonly
PR#61: changes to the deployment would be untestable before the merge.
#selfdeploy.temurin
PR#62: each Java update would mean about 1 GB uploaded by hand.
#security.login
Security audit: public read access is a requirement.
#security.robotsinit
PR#25: when Werkator serves robots.txt itself, it covers Apache and nginx.
#ops.spa
ADR 0004: polling is enough.
#ops.compose
ADR 0005: an external compose stack is manual work for every operator.
#ops.graal
ADR 0006: Spring AOT cannot hold CLI mode and server mode in one image.
#ops.container
ADR 0006: socket mounts, a HOME at the same path and uid mapping.
#forgejo.s3
Includes afterSuccessOf as a list.
#forgejo.free
ADR 0010: the own format stays expressible as a workflow.
#forgejo.replace
ADR 0010: the workflow format needs uses:, expressions and matrix; Werkator would be a second runner.
#tests.frameworks
ADR 0001: Kotest is more idiomatic; Spek has stalled.
#tests.executorit
PR#97: about one more hour per run.
#tests.xmx512
PR#134 gave MEMORY_ERROR; PR#135 reverted it.
#tests.origin
PR#52: it fails every branch that is merely out of date.