Files
werkrevisor/.werkrevisor.toml
claude-code e8b256ef92
werkator build succeeded after 00:22
werkrevisor 0.14.0: severity of the model findings (#14)
werkrevisor 0.14.0: the severity of the model findings decides between ORANGE and YELLOW.

- The model marks every finding as `[high]`, `[medium]` or `[low]`; werkrevisor reads and strips the mark.
- ORANGE needs one high finding or `[review] orange_min_medium` (default 2) medium ones; other findings give YELLOW.
- `[review] orange_min_medium` replaces `red_min_findings`.

Details: the PR document under `docs/prs/`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed-on: #14
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-05 20:39:29 +02:00

184 lines
7.8 KiB
TOML

# werkrevisor repository config: the review rules of this repository.
# werkrevisor reads this file at the base commit of a PR, so a PR cannot change its own review;
# a change takes effect after the merge and always needs a human approval.
# Model, prices, budget, gate and engine come from the host config, see config/werkrevisor.toml.
[size]
# Changed lines and files outside the docs; above them a human approves knowingly (ORANGE).
max_changed_lines = 800
max_files = 30
[categories]
docs = ["**/*.md", "docs/**"]
tests = ["tests/**"]
main = ["werkrevisor/**"]
api_spec = ["**/openapi*.yaml", "**/openapi*.yml"]
auto_approvable = ["docs_only", "tests_only_added", "docs_and_tests", "refactoring", "feature_with_tests", "harmless_only", "mechanical_only"]
[hard_yellow]
# These paths are added to those of the host config.
paths = [
# The operator config, the image and the CI decide what the gate does.
"config/**", "Dockerfile*", ".dockerignore", "tools/build-rootfs", ".werkator*", ".gitea/**",
# These modules hold the trust boundary: tokens, redaction, the HOME guard and the Gitea writes.
"werkrevisor/isolation.py", "werkrevisor/redact.py", "werkrevisor/gitea.py", "werkrevisor/config.py",
"pyproject.toml", "requirements*.txt", "**/*secret*", "**/*.pem", "**/*.key", ".env*",
]
secret_scan = true
# Test data holds fake passwords; private keys and the real key formats stay flagged there too.
secret_scan_exclude = ["tests/**"]
[pr_doc]
# An open question in a changed PR document gives RED before any model call; TEMPLATE*.md and README.md never count.
globs = ["docs/prs/*.md"]
open_question_headings = ["Open Questions", "Offene Fragen"]
[review]
# Appended to the instructions of the host config.
extra_instructions = """
Write all findings in English.
Judge whether the PR document under docs/prs/ 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.
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
# One high finding or this many medium findings give ORANGE; minor findings give YELLOW.
orange_min_medium = 2
# The complete new version of each changed file follows the diff in the prompt; documentation never does.
# 120000 chars are about 34000 of the 80000 input tokens and leave about 41000 for the diff of an 800-line PR.
full_files = true
max_full_file_chars = 40000
max_full_files_chars = 120000
# 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 gives ORANGE: a human approves knowingly, and the model still reviews the PR.
enabled = true
max_line_length = 128
max_sentences_per_paragraph = 5
# Empty means the docs category.
globs = []
[classifier]
pr_doc_globs = ["docs/prs/*.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