261 lines
11 KiB
TOML
261 lines
11 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
|
||
# Longer prompts degrade the review even within the context window of a frontier model.
|
||
# The budget allows more: 2 attempts × (input × 2.00 + 10000 × 10.00) / 1M ≤ 1.00 USD gives 200000 tokens.
|
||
max_context_tokens = 150000
|
||
# Includes reasoning tokens.
|
||
max_output_tokens = 10000
|
||
reasoning_effort = "medium"
|
||
timeout_seconds = 240
|
||
max_retries = 1
|
||
# Anthropic counts more tokens than o200k_base; calibrate with prompt_tokens / counted_raw_tokens of the usage records.
|
||
# On werkrevisor PR#10 the factor 1.15 gave 49841 tokens, Anthropic reported 65792: 1.15 × 65792 / 49841 ≈ 1.52.
|
||
token_count_factor = 1.55
|
||
|
||
[budget]
|
||
max_usd_per_review = 1.00
|
||
min_key_remaining_usd = 2.00
|
||
# Only for the fallback estimate without a tokenizer: PR-Agent prompt plus AGENTS.md from repo_context_files.
|
||
prompt_overhead_chars = 30000
|
||
|
||
[size]
|
||
# Changed lines and files outside the docs; above them a human looks at the PR (YELLOW).
|
||
max_changed_lines = 1000
|
||
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", "feature_with_tests", "harmless_only",
|
||
"mechanical_only", "mixed",
|
||
]
|
||
|
||
[hard_yellow]
|
||
paths = [
|
||
"**/rbac/**", "**/*Rbac*", "**/*rbac*", "**/*Auth*", "**/*auth*", "**/*Security*", "**/*Permission*",
|
||
"**/*secret*", "**/*.pem", "**/*.key", ".env*", ".tc-environment",
|
||
".gitTally*", ".werkator*", ".gitea/**", ".github/**", "Dockerfile*", "docker-compose*", "tools/remote", ".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
|
||
# Test data holds fake passwords; private keys and the real key formats stay flagged there too.
|
||
secret_scan_exclude = ["src/test/**"]
|
||
|
||
[path_judge]
|
||
# hsadmin-ng wants a human for each change of its security, CI and build configuration.
|
||
repository_may_enable = false
|
||
# The risk categories stay those of the host.
|
||
repository_may_tune_risks = false
|
||
|
||
[pr_doc]
|
||
# An open question in a changed PR document gives RED before any model call; TEMPLATE*.md and README.md never count.
|
||
globs = ["doc/PR/*.md"]
|
||
open_question_headings = ["Open Questions", "Offene Fragen"]
|
||
|
||
[review]
|
||
extra_instructions = """
|
||
Write all findings in English.
|
||
The code-review procedure in AGENTS.md is for human reviewers and does not apply to this review:
|
||
it edits no files, so write each finding as plain text without FIXME markers.
|
||
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.
|
||
werkrevisor itself checks line length, sentences per line and sentences per paragraph of the docs;
|
||
never report these rules, not even as a style remark.
|
||
A tool writes each section of a doc from a comment `<!-- generated by … -->` up to the next heading;
|
||
report nothing about such a section.
|
||
For documentation, report only bloated or mannered prose (filler, narration of the implementation),
|
||
unclear statements, and contradictions between the PR document and 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 except the documentation;
|
||
documentation appears only in the diff.
|
||
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.
|
||
Start every issue_header with the severity of the issue: [high], [medium] or [low].
|
||
[high]: wrong behavior, data loss, a security problem or a broken contract in a realistic scenario.
|
||
[medium]: a defect with limited impact, or a missing test for changed behavior.
|
||
[low]: cosmetics, wording, log noise or style.
|
||
"""
|
||
max_findings = 3
|
||
# Without Jev, one high finding or this many medium findings give ORANGE, another medium finding YELLOW;
|
||
# with Jev, finding_real_min and finding_severity_min of the host config decide.
|
||
orange_min_medium = 2
|
||
# The complete new version of each changed file follows the diff in the prompt.
|
||
# 300000 chars are about 86000 of the 150000 input tokens and leave about 55000 for the diff of a 1000-line PR.
|
||
full_files = true
|
||
max_full_file_chars = 100000
|
||
max_full_files_chars = 300000
|
||
# PR-Agent reads AGENTS.md from the default branch, never from the PR.
|
||
repo_context_files = ["AGENTS.md"]
|
||
|
||
[writing]
|
||
# Countable rules of the writing style in AGENTS.md, checked on the changed lines of Markdown docs and PR documents.
|
||
# A violation is a hint in the comment and never blocks; the model still reviews the PR.
|
||
enabled = true
|
||
max_line_length = 128
|
||
max_sentences_per_paragraph = 5
|
||
# Empty means the docs category.
|
||
globs = []
|
||
|
||
[mechanical]
|
||
# A changed file whose every changed line is an import, a whitespace change or a rename does not go to the model.
|
||
enabled = true
|
||
# Indentation or line breaks carry meaning in these files, so a whitespace change there is never mechanical.
|
||
whitespace_significant = ["*.py", "*.yml", "*.yaml", "Makefile", "makefile", "GNUmakefile", "*.mk", "*.md",
|
||
"*.haml", "*.pug", "*.coffee", "*.nim", "*.fs"]
|
||
# Built-in import rules exist for java, kt, kts, ts, tsx, js, jsx, mjs, go and rs.
|
||
# A [mechanical.imports] table adds or replaces the line regexes of a file extension; an empty list switches it off.
|
||
|
||
[gate]
|
||
yellow_gate = "block"
|
||
human_reviewers = []
|
||
assessment_context = "ai-review/assessment"
|
||
|
||
[db_schema]
|
||
# hsadmin-ng deploys through several stages and can always restore its database,
|
||
# so only a changeset that Jev rates as risky needs a human before the merge.
|
||
judge = "jev"
|
||
|
||
[doc_check]
|
||
# Jev compares the diff of each changed file with the PR document: a contradiction, an unrelated change,
|
||
# or a change that sends customer data outside gets a line comment before a human reads the PR.
|
||
# The thresholds keep the defaults until the usage records allow a calibration on real PRs.
|
||
|
||
[engine]
|
||
# "llm": the LLM review alone; "classifier": Jev alone, no LLM; "combined": Jev, then the LLM with Jev's hints.
|
||
mode = "combined"
|
||
|
||
[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 do not count for the verdict; calibrate it with tools/jev-eval.
|
||
min_confidence = 0.3
|
||
|
||
# Every question asks for a problem: a value above red_above gives ORANGE, 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
|
||
|
||
[diagrams]
|
||
# hs-review writes them next to its draft (PR#129); the review model, Sonnet 5.5, draws them.
|
||
enabled = true
|
||
# A human reviews each of these PRs, also a GREEN one.
|
||
skip_green = false
|