268 lines
11 KiB
TOML
268 lines
11 KiB
TOML
# werkrevisor rules for werkcrappit; werkrevisor reads this file at the head of the default branch, never from a PR,
|
|
# and every change of it needs a human review.
|
|
# The host config on the review machine sets model, budget, gate and engine; see https://git.javagil.de/mi/werkrevisor.
|
|
|
|
[size]
|
|
# Changed lines and files outside the docs; above them a human looks at the PR (YELLOW).
|
|
max_changed_lines = 800
|
|
max_files = 30
|
|
|
|
[categories]
|
|
docs = ["**/*.md", "docs/**"]
|
|
tests = ["**/src/test/**", "**/src/functionalTest/**"]
|
|
main = ["**/src/main/**"]
|
|
api_spec = []
|
|
auto_approvable = [
|
|
"docs_only", "tests_only_added", "docs_and_tests", "refactoring", "feature_with_tests", "harmless_only",
|
|
"mechanical_only", "mixed",
|
|
]
|
|
|
|
[hard_yellow]
|
|
# Only secrets stay hard; the registry token of the publication is the host's, not the repository's.
|
|
paths = ["**/*secret*", "**/*.pem", "**/*.key", ".env*", ".envrc"]
|
|
# Jev judges the build, CI and publication files, and with [path_judge] scope = "all" every other file.
|
|
# A raised ratchet such as maxMutationCrap weakens the checks; a lowered one tightens them.
|
|
judged_paths = [
|
|
".gitea/**", ".github/**", ".werkator*", "tools/**",
|
|
# A leading "/" anchors at the root: the build files of the test fixtures under src/functionalTest/resources
|
|
# are test data, judged as tests.
|
|
"/build.gradle.kts", "werkcrappit-*/build.gradle.kts", "/settings.gradle.kts", "/gradle/**", "/gradle.properties",
|
|
]
|
|
secret_scan = true
|
|
# Test data holds fake passwords, so werkrevisor ignores generic `password = "..."` assignments there;
|
|
# real key formats still count there: private keys, AWS key ids, `hsak_` and `sk-or-v1-` keys (see werkrevisor's README).
|
|
secret_scan_exclude = ["**/src/test/**", "**/src/functionalTest/**"]
|
|
|
|
[path_judge]
|
|
# The host config sets scope = "all", which a repository cannot set;
|
|
# so Jev asks each changed file the risk categories of this template, as changed below.
|
|
# The 30 latest merged PRs (#16 to #45) reached no threshold; see docs/prs/2026-10-09-PR#46-risk-categories.md.
|
|
risk_template = "jvm-spring-backend"
|
|
|
|
# A Gradle and PIT plugin has no logins, SQL, transactions, migrations, stored records or REST endpoints.
|
|
[[risk.categories]]
|
|
name = "authentication"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "authorization"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "object_level_authorization"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "sql_injection"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "input_validation"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "sensitive_data_exposure"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "transaction_integrity"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "schema_migration"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "business_invariants"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "data_correction"
|
|
action = "off"
|
|
|
|
[[risk.categories]]
|
|
name = "api_compatibility"
|
|
action = "off"
|
|
|
|
# The hard invariants of AGENTS.md: a wrong metric or gate decision misleads every build that uses werkcrappit.
|
|
# Planted changes gave 0.80 to 0.91, the real files of PRs #16 to #45 at most 0.66.
|
|
[[risk.categories]]
|
|
name = "metric_integrity"
|
|
title = "Metric integrity"
|
|
question = """Does the change alter how the Mutation-CRAP value, its two inputs (mutation status and complexity) \
|
|
or the gate decision are computed, or let the plugin filter mutants, change their status or alter PIT's configuration?"""
|
|
yellow_min = 0.75
|
|
action = "yellow"
|
|
|
|
[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/20*-PR#*.md"]
|
|
open_question_headings = ["Open Questions"]
|
|
|
|
[review]
|
|
extra_instructions = """
|
|
Write all findings in English.
|
|
werkcrappit is a PIT plugin and a Gradle plugin for the Mutation-CRAP metric, in Java 21;
|
|
AGENTS.md lists its hard invariants, check each change against them.
|
|
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.
|
|
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.
|
|
# 160000 chars are about 50000 of the 150000 input tokens, counted with token_count_factor = 1.05;
|
|
# a larger prompt gets excerpts instead, then the diff only.
|
|
full_files = true
|
|
max_full_file_chars = 80000
|
|
max_full_files_chars = 160000
|
|
# PR-Agent reads AGENTS.md from the default branch, never from the PR.
|
|
repo_context_files = ["AGENTS.md"]
|
|
|
|
[writing]
|
|
# The countable rules of the writing style in AGENTS.md, checked on the changed lines of Markdown docs.
|
|
# 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
|
|
# The docs category without the generated example reports, docs/examples/mutation-crap.*, which ExampleReportsTest
|
|
# pins to what the writers write; werkrevisor has no exclude, so a new directory under docs needs a glob of its own.
|
|
globs = [
|
|
"/*.md", "docs/*.md", "docs/adr/**", "docs/rfcs/**", "docs/guides/**", "docs/prs/**", "docs/examples/README.md",
|
|
"werkcrappit-*/**/*.md",
|
|
]
|
|
|
|
[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.
|
|
|
|
[classifier]
|
|
pr_doc_globs = ["docs/prs/20*-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
|