[engine] mode chooses the review: "llm" (default, unchanged), "classifier" (Jev alone, no LLM) or "combined" (Jev, then the LLM with Jev's flagged units as hints in the user prompt). werkrevisor splits each changed PR document into ##/### sections and #### Scenario units, asks Jev once per unit with the operator's questions, and maps every answer to a problem value: each question asks for a problem, a score runs from "no problem" to "worst problem". A clear spec problem is RED, a doubtful one or an oversized unit YELLOW, a Jev error ERROR. The hints carry file, line, scenario id, question and value, but no PR text. tools/jev-eval measures the questions offline on local PR documents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
207 lines
7.7 KiB
TOML
207 lines
7.7 KiB
TOML
# werkrevisor operator config for hsadmin-ng: larger PRs, budget 1 USD per review.
|
|
|
|
[model]
|
|
id = "openrouter/anthropic/claude-sonnet-5.5"
|
|
# Operator-maintained prices in USD per 1M tokens, from the OpenRouter models API on 2026-10-04.
|
|
input_price_usd_per_mtok = 2.00
|
|
output_price_usd_per_mtok = 10.00
|
|
# Sized so that the worst case of both attempts stays within max_usd_per_review.
|
|
max_input_tokens = 190000
|
|
# Includes reasoning tokens.
|
|
max_output_tokens = 10000
|
|
reasoning_effort = "medium"
|
|
timeout_seconds = 240
|
|
max_retries = 1
|
|
|
|
[budget]
|
|
max_usd_per_review = 1.00
|
|
min_key_remaining_usd = 2.00
|
|
# PR-Agent prompt plus AGENTS.md from repo_context_files.
|
|
prompt_overhead_chars = 30000
|
|
|
|
[size]
|
|
max_changed_lines = 1500
|
|
max_files = 40
|
|
|
|
[categories]
|
|
docs = ["**/*.md", "doc/**", "docs/**"]
|
|
tests = ["src/test/**"]
|
|
main = ["src/main/**"]
|
|
api_spec = ["src/main/resources/api-definition/**"]
|
|
auto_approvable = ["docs_only", "tests_only_added", "docs_and_tests", "refactoring"]
|
|
|
|
[hard_yellow]
|
|
paths = [
|
|
"**/rbac/**", "**/*Rbac*", "**/*rbac*", "**/*Auth*", "**/*auth*", "**/*Security*", "**/*Permission*",
|
|
"src/main/resources/db/changelog/**", "**/*.sql",
|
|
"**/*secret*", "**/*.pem", "**/*.key", ".env*", ".tc-environment",
|
|
".gitTally*", ".werkator*", ".gitea/**", ".github/**", "Dockerfile*", "docker-compose*", "tools/**", ".aliases",
|
|
"build.gradle*", "settings.gradle*", "gradle/**", "buildSrc/**", "gradle.properties",
|
|
"package.json", "package-lock.json", "pyproject.toml",
|
|
"src/main/resources/application*.yml", "src/main/resources/application*.yaml",
|
|
]
|
|
secret_scan = true
|
|
|
|
[review]
|
|
extra_instructions = """
|
|
Write all findings in English.
|
|
This is a Java 25 Spring Boot application with PostgreSQL, Liquibase and a ReBAC system.
|
|
Check that comments explain why, not what.
|
|
Judge whether the PR document under doc/PR/ is clear, correct and consistent with the code.
|
|
Report only concrete problems with a realistic impact.
|
|
The user prompt contains, after the diff, the full new content of every changed file.
|
|
Check each changed line against constraints, invariants and conventions stated elsewhere in these files,
|
|
e.g. in header comments, and report a violation as a key issue.
|
|
Review the diff; use the full files only as context.
|
|
"""
|
|
max_findings = 3
|
|
red_min_findings = 2
|
|
# The complete new version of each changed file follows the diff in the prompt.
|
|
full_files = true
|
|
max_full_file_chars = 100000
|
|
max_full_files_chars = 400000
|
|
# PR-Agent reads AGENTS.md from the default branch, never from the PR.
|
|
repo_context_files = ["AGENTS.md"]
|
|
|
|
[gate]
|
|
yellow_gate = "block"
|
|
human_reviewers = []
|
|
assessment_context = "ai-review/assessment"
|
|
|
|
[engine]
|
|
# "llm": the LLM review alone; "classifier": Jev alone, no LLM; "combined": Jev, then the LLM with Jev's hints.
|
|
mode = "llm"
|
|
|
|
[classifier]
|
|
endpoint = "https://api.typesafe.ai/v1/systemone"
|
|
model = "jev-latest"
|
|
# Operator-maintained price in USD per 1M input tokens; Jev's output is free.
|
|
input_price_usd_per_mtok = 0.042
|
|
# Jev reads about 32000 tokens of state; a larger unit is not sent and makes the review YELLOW.
|
|
max_state_chars = 60000
|
|
max_units = 80
|
|
timeout_seconds = 20
|
|
pr_doc_globs = ["doc/PR/*.md"]
|
|
# Choice and score answers below this confidence give YELLOW; calibrate it with tools/jev-eval.
|
|
min_confidence = 0.3
|
|
|
|
# Every question asks for a problem: a value above red_above gives RED, above yellow_above YELLOW.
|
|
# A score's criteria run from "no problem" to "worst problem"; its value is the normalized expected level.
|
|
|
|
[[classifier.scenario_questions]]
|
|
name = "hard_to_read"
|
|
type = "score"
|
|
instructions = """
|
|
`scenario` is a Gherkin scenario from a pull-request document; `feature` and `background` give its context.
|
|
Domain experts who do not program approve these scenarios as the specification.
|
|
How hard is the scenario to understand for such a domain expert?
|
|
The text may be German or English.
|
|
"""
|
|
criteria = [
|
|
"A domain expert understands the scenario at the first reading.",
|
|
"A domain expert understands it, but must read some steps twice.",
|
|
"A domain expert needs a developer to explain parts of it.",
|
|
"A domain expert cannot tell what the scenario requires.",
|
|
]
|
|
red_above = 0.75
|
|
yellow_above = 0.5
|
|
|
|
[[classifier.scenario_questions]]
|
|
name = "more_than_one_aspect"
|
|
type = "noul"
|
|
instructions = """
|
|
Does the Gherkin scenario in `scenario` specify more than one independent business rule or aspect,
|
|
so that it should be split into two or more scenarios?
|
|
Variants of the same rule that differ only in their data count as one aspect.
|
|
A second When with its own Then that checks a different case counts as a second aspect.
|
|
"""
|
|
red_above = 0.85
|
|
yellow_above = 0.6
|
|
|
|
[[classifier.scenario_questions]]
|
|
name = "implementation_details"
|
|
type = "noul"
|
|
instructions = """
|
|
Does the Gherkin scenario in `scenario` describe implementation details instead of business behaviour,
|
|
for example class, method, table or column names, SQL, internal HTTP headers or JSON internals?
|
|
Naming the public API endpoint, the HTTP method, the response status and the business fields
|
|
counts as observable behaviour, not as an implementation detail.
|
|
"""
|
|
red_above = 0.85
|
|
yellow_above = 0.6
|
|
|
|
[[classifier.scenario_questions]]
|
|
name = "given_when_then_misused"
|
|
type = "noul"
|
|
instructions = """
|
|
Does the Gherkin scenario in `scenario` misuse Given, When or Then?
|
|
Misuse is: an action or API call in Given, an expected result or check in When,
|
|
an action in Then, or a Then without a preceding When.
|
|
And-steps belong to the keyword above them.
|
|
"""
|
|
red_above = 0.85
|
|
yellow_above = 0.6
|
|
|
|
[[classifier.scenario_questions]]
|
|
name = "vague_then"
|
|
type = "noul"
|
|
instructions = """
|
|
Does a Then step of the Gherkin scenario in `scenario` lack a checkable outcome,
|
|
for example "works", "is handled correctly" or "behaves as expected",
|
|
without saying what an observer can check?
|
|
"""
|
|
red_above = 0.85
|
|
yellow_above = 0.6
|
|
|
|
[[classifier.section_questions]]
|
|
name = "hard_to_understand"
|
|
type = "score"
|
|
instructions = """
|
|
`section` is a section of a pull-request document that a human reviewer reads before the code.
|
|
How hard is the section to understand for a reviewer who knows the project but not this change?
|
|
Markdown lists, tables, links and code identifiers are normal here.
|
|
The text may be German or English.
|
|
"""
|
|
criteria = [
|
|
"The reviewer understands the section at the first reading.",
|
|
"The reviewer understands it, but must read some sentences twice.",
|
|
"The reviewer must guess what some sentences mean.",
|
|
"The reviewer cannot tell what the section says.",
|
|
]
|
|
red_above = 0.75
|
|
yellow_above = 0.5
|
|
|
|
[[classifier.section_questions]]
|
|
name = "slop"
|
|
type = "score"
|
|
instructions = """
|
|
How much of `section` is slop: filler words, mannered or promotional prose,
|
|
narration of the implementation instead of the reasons, or repetition of what other sentences already say?
|
|
Plain lists, tables, links and code identifiers are not slop.
|
|
The text may be German or English.
|
|
"""
|
|
criteria = [
|
|
"No slop: every sentence carries information.",
|
|
"A few filler words or one redundant sentence.",
|
|
"Several sentences are filler, mannered prose, narration or repetition.",
|
|
"The section is mostly filler, mannered prose, narration or repetition.",
|
|
]
|
|
red_above = 0.75
|
|
yellow_above = 0.5
|
|
|
|
[[classifier.section_questions]]
|
|
name = "writing_rules_violated"
|
|
type = "noul"
|
|
instructions = """
|
|
The writing rules for these documents are:
|
|
one sentence per line, and a sentence longer than 128 characters wraps at a comma, colon or before "and"/"or";
|
|
short sentences; active voice where it is natural;
|
|
simple, literal words as in ASD-STE100 Simplified Technical English; one term for one concept;
|
|
no mannered prose; enumerations as lists; code identifiers and established technical terms stay as they are.
|
|
Does `section` clearly violate these writing rules?
|
|
Tables, link lists and code blocks do not count as violations.
|
|
The text may be German or English.
|
|
"""
|
|
red_above = 0.85
|
|
yellow_above = 0.6
|