#

## v1.2.0 — 2026-09-03

- The build sandbox for hosts without Docker is configured as `werkdock` now, not `bwrap` (PR#19), and its `bwrap.werkdock` key — which named its own executor — is `werkdock.binary`. The old section is still read, with a warning naming the file, so no installation has to be changed before its next configuration edit. `bwrap` named the mechanism one layer below the tool that actually runs it: builds have been executed by the werkdock CLI since v1.0.0.

## v1.1.2 — 2026-09-03

- On a Hostsharing Managed Webspace, an `instance-update` restart no longer looks dead while nothing is listening on the port for a moment: the generated `.htaccess` (PR#17) now maps a refused connection to a static "Werkator is restarting — please retry in a few minutes" page instead of Apache's default error page. Generated only where a `server.publicBaseUrl` is configured, next to the existing `.htaccess`; nothing changes for a Docker-host deployment.

## v1.1.1 — 2026-09-03

- The system page's disk metric is now quota-aware (PR#16): it shows the tightest of the user quota, the group quota, and the volume itself, instead of always the volume. On a Hostsharing Managed Webspace that is usually a group quota, far tighter than the shared host disk — the info line names the binding source and its hard limit, and the warn/critical highlighting now fires against the real budget. A host without a binding quota renders exactly as before.

## v1.1.0 — 2026-09-03

- One instance can now serve several repositories (ADR 0009): a `~/.werkator.yml` lists them, and each is worked on through its own `RepoContext` — checkout, results, artifact store, and worktrees never share state across repositories. The watcher polls every registered repository in its own guard, and the executor's `maxConcurrent` still applies per `(repository, branch)`, not just per branch.
- Server routes carry the repository as `/repos/<name>/…` and `/api/repos/<name>/…`; the unscoped routes keep meaning the served repository, so a single-repository installation notices nothing. `build`, `retry`, and `status` take a `--repo` option to pick a registered repository instead of always acting on the current directory.
- The system page's resource metrics are sampled and reported per repository instead of once for the whole instance.
- The page title carries a drop-down next to the heading in place of the plain repository name once more than one repository is registered — picking a different one switches straight to the same view (Branches, History, …) on it. A single-repository installation still shows the plain name, unchanged.

## v1.0.1 — 2026-08-31

- The restart button on the Branches view builds the branch's current head instead of repeating the commit its last build ran on, and says so: it reads "Build current head" there. A row on that page is a branch, not a past run — and repeating an overtaken commit can be worse than useless, because a build gate comparing the built commit against origin can never pass on it. The row keeps its build definition, and a branch that is gone from origin is refused by name instead of quietly falling back to the old commit.
- Latest and History are unchanged: a row there is a recorded run, and restarting it means that commit.

## v1.0.0 — 2026-08-31

- GitTally is now Werkator. The old name already belongs to another product in the git space, so the rename is a precaution and nothing more: what the build system does, how it is configured, and how it reports to Gitea are unchanged. In prose it is Werkator, everywhere a machine reads the name it is `werkator`. The version marks the new name rather than a claim about maturity: the release after `0.9.21` is `1.0.0`, because a product that changes its name is better off counting from one under it.
- The rename reaches the file names an installation depends on. The committed configuration is `.werkator.yml`, the machine-specific one `.git/werkator/.werkator.yml`, and all state — build results, artifacts, worktrees, the control token — lives under `.git/werkator/`.
- The default Gitea check context is `werkator`. Where the old name is pinned in a branch protection rule, the rule has to be updated with it, or a pull request waits forever for a check nobody posts any more. Statuses already written keep their old context, so a commit built before and after the change shows both.

## v0.9.21 — 2026-08-30

- An origin the watcher cannot reach is now visible in the web UI: a banner above the table says that the list below is not updating, since when, and why. Until now the page kept showing its last known state, calm and plausible, while GitTally had not been able to fetch for an hour — the failure lived in the log alone. The banner is deliberately separate from the live indicator: that one says whether your browser reaches the server, this one whether the server reaches origin.
- A lasting fetch failure is logged when its message changes instead of on every poll cycle, and the recovery is logged once. One wrong token used to write several hundred identical warnings an hour. An invalid `atTimes` slot is likewise reported once per slot.

## v0.9.20 — 2026-08-29

- A build definition is now split in two: a `trigger` block says when the build runs and for which branches (`onPush`, `atTimes`, `branches`, `activeWithin`), everything beside it says what the build does. Only the second half is inherited from `builds.default`, and making that structural means a selector added later cannot become inheritable by accident. A definition still writing those keys flat is refused by name — a trigger nobody reads any more is a build that silently stops running.
- A branch pattern prefixed with `!` excludes instead of selecting, and an exclusion wins whatever the order: `branches: ["*", "!master"]` is every branch but master. That lets one branch have a build of its own without being built by the default one as well — previously the only way to avoid the double build was to give up the second definition's push trigger.
- A build may report under its own Gitea check with `statusContext`; empty keeps the repository-wide `gitea.statusContext`. Two builds of one commit used to overwrite each other's result there, so a second build over the same branch — a quick check next to a long one — was not readable in Gitea.
- Fixed: a branch whose builds all belong to named definitions showed an empty row in the branches view, reading as "never built" right next to its actual builds.

## v0.9.19 — 2026-08-29

- A build definition now describes its build completely: `requirePullRequest` and the whole `docker` section, the sandbox policy included, live in `builds.<name>`. `builds.default` is the base every other definition inherits its settings from — never its trigger, because `onPush`, `atTimes`, `branches`, and `activeWithin` say when and where that one build runs.
- The per-branch `branches` section is thereby superseded and will be removed. It is still read, but only while nothing defines a build at all: as soon as one real definition exists — a leftover `builds.maxConcurrent` is not one — `branches` is ignored completely and a warning names it. Either or, never both: two half-answers to what a build runs would pull against each other.
- `requirePullRequest`, `docker.enabled`, and `docker.network` stay pinned to the host, wherever a branch writes them. Since the inheritance is applied after all configuration layers are merged, a build a branch invents and the host has never heard of still inherits the host's `builds.default` — it cannot reach a native build by defining a new job.
- Fixed: the archived artifact directories came from the plain branch settings, so a build definition adding its own `artifactDirs` — a release job storing `build/libs`, say — never had them stored.
- Fixed: the build definitions of a branch were cached by its head commit alone, so an edited machine or project configuration only took effect once that branch moved. On a quiet branch, a new scheduled job never started at all.

## v0.9.18 — 2026-08-29

- A configuration file can declare which GitTally it is written for, so a version that renames or drops a key says so instead of silently ignoring what it no longer understands: `gitTally: { version: { since: "0.9.18", below: "2.0" } }`. `since` is enforced — both against a GitTally that is too old and against a file written before the version in which the configuration format last changed incompatibly, which GitTally knows about itself. `below` is a release marker and only warns, so an unmaintained value can never stop a build.
- The reach follows the file: the machine and project configuration abort the start naming the file and the way back, an incompatible configuration committed on a branch fails only that branch's builds. A file that declares nothing keeps working, and `gittally init` writes the current version into the config it generates.

## v0.9.17 — 2026-08-29

- Fixed: a page left in the background — a phone tab switched away from for an hour — kept showing the state it was left in, with the durations of running builds counting up client-side although the builds had long finished. A returning page now fetches the current state immediately, whether the browser reports the return as a visibility change, a focus, or a restore from its cache.

## v0.9.16 — 2026-08-29

- A scheduled build can run hourly: `atTimes: ["??:05"]` stands for that minute of every hour. Each hour is its own slot, so it triggers once per hour — mixing it with fixed `HH:MM` times works, the latest due slot wins. Only the hour may be a wildcard; anything else is skipped with a warning.
- Fixed: the artifact page showed the build command of the plain branch configuration — for a build of a named definition, or on a branch whose committed `.gittally.yml` overrides the command, that was a command the build never ran. It now shows what this build actually runs, resolved from the branch configuration committed at the build's own commit plus its definition.

## v0.9.15 — 2026-08-29

- The `.gittally.yml` committed on a branch now takes precedence for the `builds` section as well — a branch can define its own build definitions and override those from the project config. The watcher reads each origin branch's committed configuration, so a new build definition takes effect by committing it on a branch, without touching any other branch's builds. A branch's definitions apply to that branch alone.
- Pinned to the server side are only the keys that do not describe the branch's build: secrets (`git`), the host and repository sections (`server`, `gitea`, `executor`, `watcher`), the container sandbox policy (`docker.enabled`, `docker.network`), and the `requirePullRequest` gate.
- Changed: the build concurrency limit moved from `builds.maxConcurrent` to `executor.maxConcurrent` (default 1, no compatibility alias) — the `builds` section now holds build definitions only. A leftover `builds.maxConcurrent` key is ignored with a warning instead of failing the configuration, so an installation keeps running until its committed config can be updated.

## v0.9.14 — 2026-08-28

- Named build definitions (ADR 0007): the `builds` section of `.gittally.yml` now defines jobs with `onPush`/`atTimes` triggers, branch selectors (name globs, `activeWithin` age filter), and overrides of the branch settings — e.g. a nightly `pitest` build running a fuller check than the quick on-push builds. A named build records under its own `<branch>@<build>` pool with its own branches-view row, retention count, and permanent latest-green artifact link.
- Restart, `gittally retry`, and the startup recovery re-run a build under its recorded definition, resolving the settings from the current configuration.
- Changed: the v0.9.13 per-slot `buildCommand`/`name` syntax in `autoBuild.times` is gone again — use a build definition instead. `branches.*.autoBuild` with plain times keeps working but is deprecated.

## v0.9.13 — 2026-08-28

- A scheduled auto-build slot (`autoBuild.times` entry) can carry its own `buildCommand`, so a nightly slot runs a fuller check than the quick on-commit builds of the same branch. Restart, retry, and the startup recovery repeat a build with the command it originally ran.
- A slot can also carry a `name` (e.g. `master@nightly`): its builds then get their own row in the branches view, their own history and retention pool, and their own permanent latest-green artifact link (`/branches/master_nightly/…`) — the branch's regular builds no longer displace the nightly build and its artifacts.

## v0.9.12 — 2026-08-26

- A build whose branch is deleted from origin mid-build (the usual fate of a merged branch) no longer vanishes from the UI and history while it is still queued or running — previously the queue looked stuck although a build was executing.
- Triggering a build that is already queued or running for the same commit no longer stacks a duplicate — an impatient double-click on restart now hits the existing build. Re-running a finished build is unaffected.

## v0.9.11 — 2026-08-14

- At the end of each poll cycle, the local branch refs of the watched repository are fast-forwarded to their state on origin, so build steps that compare a branch with its origin counterpart no longer fail once origin moved on. Only fast-forwards are applied — a branch that diverged from origin or is ahead of it stays untouched. Switched off with `watcher.fastForwardLocalRefs: false`.
- On the artifact index of a failed build, the logs that actually contain the build tool's failure line carry a failed badge — with stdout and stderr stored separately, that points straight at the log worth opening. Logs of a green build are not scanned.

## v0.9.10 — 2026-08-11

- The control token is no longer embedded in the pages — reading them is unauthenticated, so anyone could have picked it out of the HTML. Viewing stays public; the first click on a restart/cancel/delete button asks for the token once (it is in `.git/gittally/control-token` on the host) and keeps it in the browser.

## v0.9.9 — 2026-08-11

- Changed default: `server.bindAddress` is now `127.0.0.1` instead of `0.0.0.0`, because neither the UI nor the API authenticates read access. Existing `.gittally.yml` files keep whatever they set; with the managed nginx container, `0.0.0.0` has to be set explicitly.
- The control token is accepted in the `X-GitTally-Token` header only — the `token` query parameter is gone, as URLs end up in access logs and browser history.
- `config:print` masks `git.token`; `--show-secrets` prints it.
- Files holding secrets (the Gitea token written by `init`, the control token) are created with mode `0600` right away instead of being `chmod`-ed afterwards, the control token is compared in constant time, and git calls pass `--` before branch names.
- On narrow screens the page title and the repository name are stacked instead of wrapping.

## v0.9.8 — 2026-08-10

- The artifact index also links report pages of directories without an `index.html`. A directory holding a single page is linked as a directory, so Gradle's `--profile` report keeps a stable URL although its file name carries the build timestamp.
- The permanent `🔗` link now appears on the build it resolves to — the branch's latest green build — instead of on every build of that branch, and on all build tables.
- The Current tab gave way to a `📡` link in the artifacts column, shown while a build runs.

## v0.9.7 — 2026-08-10

- `init --systemd` also installs a nightly Docker cleanup timer (`gittally-docker-prune.timer`, 02:00 host time): stopped containers and unused images are pruned before the auto builds — like the legacy host, but the per-repository Gradle cache volumes survive.

## v0.9.6 — 2026-08-10

- This release-notes page, linked from the version in the footer.
- Mobile: the live indicator collapses to a colored state dot so it no longer squeezes the menu.
- The system page highlights critical utilization: the current value of CPU, RAM, and disk used turns orange from 80% and red from 90% of the respective total.

## v0.9.5 — 2026-08-10

- Builds killed by a server shutdown (e.g. a deployment restart) are recorded as interrupted instead of failed, publish a pending Gitea status, and are re-enqueued when the server starts again.

## v0.9.4 — 2026-08-10

- The legacy page names (`/index.html`, `/branches.html`, …) answer with permanent redirects to the new routes, so pre-rewrite bookmarks and the redirect from the old host keep working.

## v0.9.3 — 2026-08-10

- The artifact page shows a n failed badge behind links to test reports that contain failures.

## v0.9.2 — 2026-08-10

- Cancelling a build also terminates its auxiliary phases (Docker image build, Gradle cache volume preparation), so the next queued build starts immediately.

## v0.9.1 — 2026-08-10

- Durations no longer flicker while live-updating.
- While a build is running or pending, the artifact link shows an hourglass (logs only, so far) instead of the report icon.
- Pending builds show their queue wait time in italics; running and finished builds show the pure build time without the wait.

## v0.9.0 — 2026-08-10

Port of the legacy gitTally bash script to Kotlin/Spring Boot — the first production deployment of the rewrite.

- Dual-mode application: CLI (`init`, `status`, `build`, `retry`, `config:print`) and HTTP server with this web UI and a JSON API.
- Declarative YAML configuration: committed `.gittally.yml` plus machine-specific overrides and secrets under `.git/gittally/`.
- Builds run detached in git worktrees — the primary checkout is never used for builds.
- Docker build containers with automatic image rebuilds and a per-repository Gradle cache volume; works under rootless Docker daemons; git metadata is available read-only inside the container.
- Branch watcher with auto-builds (nightly slots), a pull-request gate, and pruning of results, artifacts, and stale worktrees.
- Commit statuses reported to Gitea; artifact store with per-branch retention and permanent latest-green links; system metrics page.
- Managed nginx/TLS container (Let's Encrypt) for hosts without a reverse proxy; `init --systemd` generates the service unit.
- Self-contained runtime bundle (jlink-trimmed JRE + jar) for hosts without a Java runtime.