fabro/.fabro/workflows/code-review/code-review.fabro
2026-08-28 15:32:01 -04:00

247 lines
12 KiB
Text

digraph CodeReview {
graph [
goal="Review the committed change with independent discovery jobs -- one single pass at low; grouped local-correctness passes, whole-change angles, and path-matched rule audits at every tier above -- verify every surviving candidate, and report only findings that pass.",
default_max_retries=0,
default_fidelity="compact",
on_failure="exit",
stall_timeout="14400s",
model_stylesheet="
{% set tiers = ['low', 'medium', 'high', 'xhigh', 'max'] %}
{% set effort = inputs.effort if inputs.effort in tiers else 'medium' %}
{% if 'kimi' in inputs.model %}
{% set finders = {'low': 'low', 'medium': 'high', 'high': 'high', 'xhigh': 'max', 'max': 'max'} %}
{% set verifiers = {'low': 'low', 'medium': 'high', 'high': 'high', 'xhigh': 'high', 'max': 'high'} %}
{% set sweeps = {'low': 'low', 'medium': 'high', 'high': 'high', 'xhigh': 'max', 'max': 'max'} %}
{% else %}
{% set finders = {'low': 'low', 'medium': 'medium', 'high': 'high', 'xhigh': 'xhigh', 'max': 'max'} %}
{% set verifiers = {'low': 'low', 'medium': 'medium', 'high': 'medium', 'xhigh': 'high', 'max': 'xhigh'} %}
{% set sweeps = {'low': 'low', 'medium': 'medium', 'high': 'high', 'xhigh': 'xhigh', 'max': 'xhigh'} %}
{% endif %}
* { model: {{ inputs.model }}; reasoning_effort: {{ finders[effort] }}; }
.grouping { model: {{ inputs.model }}; reasoning_effort: low; }
.verification { model: {{ inputs.model }}; reasoning_effort: {{ verifiers[effort] }}; }
.sweep { model: {{ inputs.model }}; reasoning_effort: {{ sweeps[effort] }}; }
"
]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
prepare [
shape=parallelogram,
label="Resolve and size the review target",
timeout="300s",
output_schema="routing",
stdin_source="context.internal.run_id",
script="python3 -c \"import hashlib,sys; pairs=list(zip(sys.argv[1::2],sys.argv[2::2])); sys.exit(0 if pairs and all(hashlib.sha256(open(path,'rb').read()).hexdigest()==expected for path,expected in pairs) else 91)\" .fabro/workflows/code-review/scripts/code_review.py 78d239edb68be8e3db983445a786b9dca7eed6044ff4430e5581ae4c4c8466d3 .fabro/workflows/code-review/scripts/git_readonly.py 29cee508724f7bee8d73317d82fe94d0d830361476b367e4a012b70071a0e841 .fabro/workflows/code-review/scripts/publish_pr.py 35cde9006c9d079f468228498704c7c6079bff52fc790d7e2cee9505d3de9a06 .fabro/workflows/code-review/scripts/render_report.py fe432d8a53e1294b8030a54ca17b412312338e761ee751ab770e221450b53b8c .fabro/workflows/code-review/scripts/review_contract.py 8917fe7ae046cfda547f4f1240570fa295e110fd5e8d0c84c2a98719137db6fa .fabro/workflows/code-review/scripts/rule_loader.py eaa7258e5cf7b231a7a1192c9738eb2a0486480cd04ebe2059a79295040fc66e .fabro/workflows/code-review/specs/report-spec.md 7a54f72ee46f09218d18854d184a1f36875f9011877e94779c6b1f0d5dd118a9 .fabro/workflows/code-review/templates/report.html 5def570da34ca186da31781378367d70fb9c58e82f7aeec4aaf420fd348a8e61 .fabro/workflows/code-review/schemas/findings.schema.json 2f4d0a9052d5af0dad92db12a1e9d49cc91a282c4dddda495791352bf1559ed8 .fabro/workflows/code-review/schemas/verdict.schema.json de13ce02c5fd0c088640542831cc732e35dee3ddb38f89d4412f6a46fea75567 .fabro/workflows/code-review/schemas/file-groups.schema.json b53c4e1c0bbd07bbf70e83f4f3b35fd96cb880c621c7c424e95b9aea34e13d7c .fabro/workflows/code-review/prompts/finder.md.j2 86c2e6a032f7c54c1bbab1c12496a8f0d6bf48703abe6017eb175330608cf223 .fabro/workflows/code-review/prompts/verify.md.j2 cb3866240077d1bc8993b2f012a8d66a6ea61d4a9f2e88a1fefc6ef375f630e2 .fabro/workflows/code-review/prompts/sweep.md.j2 e6f89b47b11c57030a6ef7d5896ccb37dbd2a2982e9fa7eb7f2e3df73acab82c .fabro/workflows/code-review/prompts/group-files.md.j2 5b291313a1266d1d658f80ea7989cdefcd8609b6893b7197b17914d553dab041 .fabro/workflows/code-review/prompts/partials/finding-fields.md.j2 a81ee5b0ac134eb121dbf503025387c64126d3276e4673ebc836cfb62a3689fb .fabro/workflows/code-review/prompts/partials/guidance.md.j2 53bc0c40bb917288708bed1f9ba478fbd89b9790c92497762224cc752f40bef5 .fabro/workflows/code-review/prompts/partials/output-schema.md.j2 811994bb357739f2562d84f66dc05075ebe3c7f8d58034f8c25ee1c36bee996b .fabro/workflows/code-review/prompts/partials/read-only-explorer.md.j2 44a0244e7aa62fdb0dbbfdbadcffbfb640af249bae3e96895dedd5c7a33bad10 .fabro/workflows/code-review/prompts/partials/review-target.md.j2 abffeeff0e16b89a0754cd53f1833b3744494cd54ff761798b782a80467446ea .fabro/workflows/code-review/prompts/partials/safe-git-history.md.j2 4ddd8d36d5c51d7e166a6b7f1dff51b72cce0e64108cc7e892002ca909af8b3a .fabro/workflows/code-review/rules/builtin-manifest.json ecd1d77ad8c77cae153280cb775e5e5f7fa9b68925900473e7d2331af377bb49 && python3 .fabro/workflows/code-review/scripts/code_review.py prepare --review-id-stdin --mode {{ inputs.mode }} --effort {{ inputs.effort }} --scope {{ inputs.scope }} --base {{ inputs.base }} --commit {{ inputs.commit }} --range {{ inputs.range }} --model {{ inputs.model }} --guidance {{ inputs.guidance }}"
]
grouping [
label="Group target files",
class="grouping",
prompt="@prompts/group-files.md.j2",
output_schema="@schemas/file-groups.schema.json",
output_retries=2,
max_retries=2,
on_failure="route",
timeout="1800s",
project_memory=false
]
merge_grouping [
shape=parallelogram,
label="Merge the grouping proposal",
stdin_source="context.output.grouping",
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge grouping",
output_schema="routing",
timeout="180s"
]
plan_finders [
shape=parallelogram,
label="Plan discovery jobs",
timeout="180s",
output_schema="routing",
script="python3 .fabro/workflows/code-review/scripts/code_review.py plan-finders"
]
finders [
shape=component,
label="Finder jobs",
for_each="context.finder_jobs",
max_parallel=10,
on_failure="succeed"
]
finder [
label="Finder job",
class="finder",
prompt="@prompts/finder.md.j2",
output_schema="@schemas/findings.schema.json",
output_retries=2,
max_retries=2,
on_failure="succeed",
timeout="7200s",
project_memory=false
]
finder_join [shape=tripleoctagon, label="Gather finder outputs"]
merge_finders [
shape=parallelogram,
label="Merge finder outputs",
stdin_source="context.parallel.results",
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge finders",
output_schema="routing",
timeout="180s"
]
plan_verify [
shape=parallelogram,
label="Deduplicate, rank, and plan verification",
timeout="180s",
output_schema="routing",
script="python3 .fabro/workflows/code-review/scripts/code_review.py plan-verify"
]
verify [
shape=component,
label="Verify candidates",
for_each="context.verify_jobs",
max_parallel=24,
on_failure="succeed"
]
verifier [
label="Verify candidate",
class="verification",
prompt="@prompts/verify.md.j2",
output_schema="@schemas/verdict.schema.json",
output_retries=2,
max_retries=2,
on_failure="succeed",
timeout="3600s",
project_memory=false
]
verify_join [shape=tripleoctagon, label="Gather verdicts"]
merge_verify [
shape=parallelogram,
label="Merge verdicts",
stdin_source="context.parallel.results",
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge verify",
output_schema="routing",
timeout="180s"
]
tally [
shape=parallelogram,
label="Apply verdicts and plan the sweep",
timeout="180s",
output_schema="routing",
script="python3 .fabro/workflows/code-review/scripts/code_review.py tally"
]
sweeper [
label="Gap-fill sweep",
class="sweep",
prompt="@prompts/sweep.md.j2",
output_schema="@schemas/findings.schema.json",
output_retries=2,
max_retries=2,
on_failure="route",
timeout="7200s",
project_memory=false
]
merge_sweep [
shape=parallelogram,
label="Merge sweep output",
stdin_source="context.output.sweeper",
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge sweep",
output_schema="routing",
timeout="180s"
]
sweep_verify [
shape=component,
label="Verify sweep candidates",
for_each="context.sweep_verify_jobs",
max_parallel=24,
on_failure="succeed"
]
sweep_verifier [
label="Verify sweep candidate",
class="verification",
prompt="@prompts/verify.md.j2",
output_schema="@schemas/verdict.schema.json",
output_retries=2,
max_retries=2,
on_failure="succeed",
timeout="3600s",
project_memory=false
]
sweep_verify_join [shape=tripleoctagon, label="Gather sweep verdicts"]
merge_sweep_verify [
shape=parallelogram,
label="Merge sweep verdicts",
stdin_source="context.parallel.results",
script="python3 .fabro/workflows/code-review/scripts/code_review.py merge sweep_verify",
output_schema="routing",
timeout="180s"
]
final_tally [
shape=parallelogram,
label="Write the canonical review bundle",
timeout="300s",
output_schema="routing",
script="python3 .fabro/workflows/code-review/scripts/code_review.py final-tally"
]
render_report [
shape=parallelogram,
label="Derive Markdown, HTML, JSONL, and revision metadata",
timeout="300s",
output_schema="routing",
script="python3 .fabro/workflows/code-review/scripts/code_review.py render-report"
]
verify_expectations [
shape=parallelogram,
label="Verify configured report expectations",
timeout="30s",
output_schema="routing",
script="python3 .fabro/workflows/code-review/scripts/code_review.py verify-expectations --expected-min-findings '{{ inputs.expected_min_findings }}' --expected-file '{{ inputs.expected_file }}' --expected-min-rule-findings '{{ inputs.expected_min_rule_findings }}'"
]
publish_pr [
shape=parallelogram,
label="Publish findings to the reviewed PR (opt-in)",
timeout="900s",
output_schema="routing",
script="python3 .fabro/workflows/code-review/scripts/code_review.py publish-pr --post-pr '{{ inputs.post_pr }}' --pr-repo '{{ inputs.pr_repo }}' --pr-number '{{ inputs.pr_number }}' --route-severity-below '{{ inputs.route_severity_below }}' --route-categories '{{ inputs.route_categories }}' --run-url '{{ inputs.run_url }}'"
]
start -> prepare
prepare -> exit [condition="outcome=succeeded && context.empty_target=true"]
prepare -> grouping [condition="outcome=succeeded && context.use_grouping=true"]
prepare -> plan_finders [condition="outcome=succeeded && context.use_planner=true"]
prepare -> finders
grouping -> merge_grouping [condition="outcome=succeeded"]
grouping -> plan_finders
merge_grouping -> plan_finders
plan_finders -> finders
finders -> finder [fidelity="truncate"]
finder -> finder_join -> merge_finders
merge_finders -> plan_verify
plan_verify -> verify [condition="outcome=succeeded && context.run_verify=true"]
plan_verify -> tally
verify -> verifier [fidelity="truncate"]
verifier -> verify_join -> merge_verify
merge_verify -> tally
tally -> sweeper [condition="outcome=succeeded && context.run_sweep=true"]
tally -> final_tally
sweeper -> merge_sweep [condition="outcome=succeeded"]
sweeper -> final_tally
merge_sweep -> sweep_verify [condition="outcome=succeeded && context.run_sweep_verify=true"]
merge_sweep -> final_tally
sweep_verify -> sweep_verifier [fidelity="truncate"]
sweep_verifier -> sweep_verify_join -> merge_sweep_verify
merge_sweep_verify -> final_tally
final_tally -> render_report
render_report -> verify_expectations
verify_expectations -> publish_pr
publish_pr -> exit
}