# PR#27: Jev judges changes of build files instead of a fixed YELLOW > **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. ## The Problem Each change of a path in `[hard_yellow] paths` gives YELLOW, so a human has to approve the PR. For build files this is mostly noise: the PRs #24, #25 and #26 of werkrevisor got YELLOW only for the version number in `server/build.gradle.kts` or for `buildInfo()`. A real risk in a build file looks different: tests switched off, failures ignored, a threshold lowered, or a script downloaded from an unknown host. Such a change deserves more than YELLOW, but the fixed rule cannot tell it from a version number. Some paths must stay a fixed YELLOW, though: hsadmin-ng wants a human for each change of its security, CI and build configuration. ## Non-Goals - No change of `[hard_yellow] paths`: these paths keep their fixed YELLOW, without Jev. - No judgment of the built-in hard paths, e.g. `.werkrevisor.toml`: a repository config change always needs a human. - No judgment by the LLM: Jev answers two fixed questions, and the thresholds come from the measurement below. ## The Scenarios ### Background - **Given** `[hard_yellow] judged_paths` holds `server/*.gradle.kts` - **and** `[path_judge] judge = "jev"` ### Feature: Jev judges a change of a judged path #### Scenario#27.01: Jev's answers decide the color of a judged path So that a routine build change needs no human, and a weakened check gets more attention than YELLOW. - **Given** a PR changes `server/build.gradle.kts` by `` - **When** werkrevisor reviews the PR - **and** Jev answers `` for "weakens checks" and `` for the build risk - **Then** the path gives `` | change | weakens | risk | color | |---|---|---|---| | a new version number | 0.02 | 0.00 | GREEN, as a hint | | `buildInfo()` added | 0.03 | 1.27 | GREEN, as a hint | | a major upgrade of the toolchain | 0.15 | 1.90 | YELLOW | | `ignoreFailures = true` for the tests | 0.97 | 2.76 | ORANGE | | a script from an unknown host run before the compile step | 0.13 | 3.00 | ORANGE | ##### Verified by - [test_pathjudge: test_jev_answers_decide_the_verdict](../../tests/test_pathjudge.py) #### Scenario#27.02: a path that Jev could not judge stays YELLOW So that an outage of Jev never makes a build change GREEN. - **Given** a PR changes `server/build.gradle.kts` - **When** werkrevisor reviews the PR `` - **Then** the path gives YELLOW, with the reason "build files not judged by Jev" | case | |---| | and Jev fails | | and the diff holds a possible secret, which must not reach Jev | | with `--no-llm` | | and the PR deletes the file | | and the file has no text diff | ##### Verified by - [test_pathjudge: test_unjudged_paths_give_yellow](../../tests/test_pathjudge.py) - [test_pathjudge: test_deleted_or_empty_judged_files_are_not_judged](../../tests/test_pathjudge.py) #### Scenario#27.06: a renamed judged file gives YELLOW without Jev So that moving a build file out of its place needs a human; the diff of its content does not show the move. - **Given** a PR renames `server/build.gradle.kts` - **When** werkrevisor reviews the PR - **Then** the file gives YELLOW as a risky path - **and** Jev is not asked ##### Verified by - [test_pathjudge: test_a_renamed_judged_file_is_a_risky_path](../../tests/test_pathjudge.py) ### Feature: hard paths stay hard #### Scenario#27.03: a path in both lists stays a fixed YELLOW So that a judged path of the repository config cannot soften a hard path of the host config. - **Given** the host config lists `build.gradle*` in `[hard_yellow] paths` - **and** the repository config lists `build.gradle.kts` in `[hard_yellow] judged_paths` - **When** werkrevisor reviews a PR that changes `build.gradle.kts` - **Then** the path gives YELLOW as a risky path - **and** Jev is not asked ##### Verified by - [test_pathjudge: test_hard_paths_win](../../tests/test_pathjudge.py) #### Scenario#27.04: without the judge, a judged path gives YELLOW So that a repository that does not use Jev keeps today's behavior. - **Given** `[path_judge] judge = "never"` - **When** werkrevisor reviews a PR that changes `server/build.gradle.kts` - **Then** the path gives YELLOW as a risky path ##### Verified by - [test_pathjudge: test_never_judge_gives_yellow](../../tests/test_pathjudge.py) ### Feature: the host decides whether a repository may switch the judge on #### Scenario#27.05: the repository config switches the judge on only if the host allows it So that hsadmin-ng can keep every listed path a fixed YELLOW, whatever its repository config says. - **Given** the host config sets `[path_judge] repository_may_enable = ` - **When** the repository config sets `[path_judge] judge = "jev"` - **Then** `` | allowed | result | |---|---| | true | Jev judges the judged paths | | false | the repository config is refused as invalid | ##### Verified by - [test_pathjudge: test_repository_may_enable_the_judge_only_if_the_host_allows_it](../../tests/test_pathjudge.py) ## The Solution - `[hard_yellow] judged_paths` lists paths that Jev judges; the host config and the repository config each add paths. A path that matches `[hard_yellow] paths` or a built-in hard path stays a fixed YELLOW. - `[path_judge]` sets `judge` (`never` or `jev`) and the thresholds; the repository config may set only `judge`, and `jev` only if the host sets `repository_may_enable = true`, the default. - Jev gets the path and the diff hunks of each judged file, with their context lines, and answers two questions: `weakens_checks` (probability) and `build_risk` (score 0 to 3). ORANGE if `weakens_checks` ≥ 0.8 or `build_risk` ≥ 2.8; GREEN as a hint if `weakens_checks` < 0.3 and `build_risk` ≤ 1.5; YELLOW otherwise. - The usage record holds `path_judgments` with the values and the color per file. - werkrevisor moves `server/*.gradle.kts`, which covers `build.gradle.kts` and `settings.gradle.kts`, to `judged_paths` and switches the judge on; `server/gradle/**` and `server/gradlew*` stay hard, since they decide which Gradle runs. - hsadmin-ng's host config sets `repository_may_enable = false`. - werkrevisor reads `.werkrevisor.toml` at the base commit, so its own judged paths take effect with the first PR after the merge; the installed werkrevisor must know the new settings by then, so 0.19.0 is deployed right after the merge. - werkrevisor 0.19.0. ## Additional Changes - The README section "How a run works" starts with a Mermaid diagram of how the workflow code, Jev and the LLM work together. ## Measurement On 2026-10-06, Jev answered the two questions for 41 diffs of build files, for 0.0022 USD in all, with the state that werkrevisor sends: - 24 changes of `build.gradle.kts` in hsadmin-ng and 3 of `server/build.gradle.kts` in werkrevisor; - 8 constructed harmful changes: tests disabled, failures ignored, tests excluded, the test task dropped from `check`, coverage and mutation thresholds lowered, a script downloaded and run, an insecure repository added; - 4 constructed harmless changes: a dependency, a module, an extra check, a raised threshold; - 2 harmful changes with a comment that calls them harmless. | group | GREEN | YELLOW | ORANGE | |---|---|---|---| | constructed harmful, also with a misleading comment | 0 | 0 | 10 | | constructed harmless | 3 | 1 | 0 | | real changes | 12 | 15 | 0 | The constructed harmless change that stays YELLOW raises a mutation threshold (`weakens_checks` 0.41). The real changes that get GREEN are version updates, new tasks and `buildInfo()`; YELLOW go, among others, the conversion to Kotlin DSL, the upgrade to JDK 25 and Spring Boot 4, and the change that bases the coverage verification on unit tests only (`weakens_checks` 0.49). Without the context lines, Jev rated `enabled = false` in a test task only 0.76 for `weakens_checks`, so it got YELLOW. ## Prerequisite PRs - PR#17: Jev judges DB changesets; this PR uses the same pattern.