# Step 01: Build State Domain and Repository

Prerequisites: none.
Read `README.md` and `00-legacy-analysis.md` first.

## Goal

A tested domain model for build results plus a persistent repository, replacing the legacy `build-results.tsv`.

## Design

Create package `de.hoennig.werkator.build`:

- `BuildStatus` enum: `PENDING`, `RUNNING`, `SUCCESS`, `FAILED`, `INTERRUPTED`, `CANCELLED`.
  Add `isTerminal`, `isRestartable` (pending/running/interrupted) properties.
- `BuildResult` data class: branch, commit SHA, status, startedAt, duration, artifactKey.
  Use `java.time.Instant`/`Duration`; format only at the edges.
- `BuildResultRepository` interface: append, update status of latest entry for a branch, query latest per branch, query history, delete entry, prune.
- `FileBuildResultRepository`: JSON file at `.git/werkator/build-results.json`.
  Write atomically (write temp file, then `Files.move` with `ATOMIC_MOVE`).
  Reuse the Jackson YAML/JSON setup style from `ConfigLoader`.

Business logic to include (port from legacy, see analysis):

- `markStaleRunningAsInterrupted()` — called at startup; running → interrupted, superseded pending → interrupted.
- Retention pruning: keep N builds per branch (`artifacts.retentionPerBranch`); drop entries for branches no longer on origin (branch list passed in as a parameter, no git dependency here).

## Out of Scope

- No git access, no Gitea, no execution — pure domain and file I/O.
- Artifact directory pruning (step 05 consumes the pruning result).
- Age-based retention (legacy supported `h`/`d` suffixes); count-based only, extend later if needed.

## Config

Uses existing `artifacts.retentionPerBranch`.
No new keys expected.

## Tests

Kotest `FunSpec`, no Spring context needed.

- Round-trip persistence, atomicity (temp file cleaned up).
- Status transition helpers and `markStaleRunningAsInterrupted` edge cases.
- Retention pruning: per-branch count, removed branches, ordering by timestamp.
- Corrupt/missing file → empty repository, no crash (legacy failed silently; we log a warning).

## Acceptance Criteria

- `./gradlew ktlintFormat` then `./gradlew build` is green.
- New code has no dependency on picocli or web classes.

## Execution Notes (done 2026-07-07)

Implemented as specified in `de.hoennig.werkator.build`; build green, 19 new tests.
Deviations and details:

- Added `jackson-datatype-jsr310` to `build.gradle.kts` for `Instant`/`Duration` JSON support (ISO-8601 strings).
- `FileBuildResultRepository` is a plain class, not a Spring bean; the file path depends on the runtime repo location, so wiring happens in step 04/06 via a factory or configuration.
- `prune(...)` and `markStaleRunningAsInterrupted()` return the removed/changed entries so step 05 can prune artifact directories and callers can log.
- Timestamp ties in `updateLatest`/`latestFor` resolve to the later appended entry.
